เครื่องมือที่มีลักษณะคล้าย grep
ซึ่งเข้าใจไวยากรณ์ของซอร์สโค้ด และช่วยให้สามารถจัดการได้นอกเหนือจากการค้นหา
เช่นเดียวกับ grep
นิพจน์ทั่วไปเป็นแกนหลักดั้งเดิม ต่างจาก grep
ตรงที่ความสามารถเพิ่มเติมช่วยให้มี ความแม่นยำสูงขึ้น พร้อมด้วย ตัวเลือกสำหรับการจัดการ สิ่งนี้ทำให้ srgn
ทำงานไปตามมิตินิพจน์ทั่วไปและเครื่องมือ IDE ( เปลี่ยนชื่อทั้งหมด , ค้นหาการอ้างอิงทั้งหมด , ... ) เพียงอย่างเดียวไม่สามารถทำได้ เสริมพวกมัน
srgn
ได้รับการจัดระเบียบตาม การดำเนินการ ที่ต้องทำ (ถ้ามี) โดยดำเนินการภายใน ขอบเขต การรับรู้ไวยากรณ์ภาษา ที่แม่นยำและเป็นทางเลือกเท่านั้น ในแง่ของเครื่องมือที่มีอยู่ ให้คิดว่ามันเป็นส่วนผสมของ tr
, sed
, ripgrep และ tree-sitter
โดยมีเป้าหมายการออกแบบ ที่เรียบง่าย : ถ้าคุณรู้จัก regex และพื้นฐานของภาษาที่คุณใช้งานอยู่ คุณก็พร้อมแล้วที่จะไป .
เคล็ดลับ
ข้อมูลโค้ดทั้งหมดที่แสดงที่นี่ได้รับการยืนยันว่าเป็นส่วนหนึ่งของการทดสอบหน่วยโดยใช้ไบนารี srgn
จริง สิ่งที่จัดแสดงที่นี่รับประกันว่าจะได้ผล
การใช้งาน srgn
ที่ง่ายที่สุดทำงานคล้ายกับ tr
:
$ echo ' Hello World! ' | srgn ' [wW]orld ' ' there ' # replacement
Hello there !
การจับคู่สำหรับรูปแบบนิพจน์ทั่วไป '[wW]orld'
( ขอบเขต ) จะถูกแทนที่ด้วย ( การกระทำ ) ด้วยอาร์กิวเมนต์ตำแหน่งที่สอง สามารถระบุการดำเนินการเป็นศูนย์หรือมากกว่าได้:
$ echo ' Hello World! ' | srgn ' [wW]orld ' # zero actions: input returned unchanged
Hello World !
$ echo ' Hello World! ' | srgn --upper ' [wW]orld ' ' you ' # two actions: replacement, afterwards uppercasing
Hello YOU !
การเปลี่ยนจะดำเนินการก่อนเสมอและระบุตำแหน่งไว้ การดำเนินการอื่นๆ จะถูกนำไปใช้หลังจากและกำหนดเป็นแฟล็กบรรทัดคำสั่ง
ในทำนองเดียวกัน สามารถระบุได้มากกว่าหนึ่งขอบเขต: นอกเหนือจากรูปแบบ regex แล้ว ยังสามารถกำหนดขอบเขต การรับรู้ไวยากรณ์ภาษาได้ ซึ่งขอบเขตไปยัง องค์ประกอบทางวากยสัมพันธ์ของซอร์สโค้ด (ลองคิดดู เช่น "เนื้อหาทั้งหมดของคำจำกัดความ class
ใน Python" ). หากระบุทั้งสองอย่าง รูปแบบนิพจน์ทั่วไปจะ ใช้เฉพาะ ภายใน ขอบเขตภาษาแรกนั้นเท่านั้น ซึ่งช่วยให้สามารถค้นหาและจัดการได้อย่างแม่นยำ ซึ่งปกติแล้วไม่สามารถทำได้โดยใช้นิพจน์ทั่วไปธรรมดา และให้บริการมิติที่แตกต่างจากเครื่องมือ เช่น เปลี่ยนชื่อทั้งหมด ใน IDE
ตัวอย่างเช่น ลองพิจารณาไฟล์ต้นฉบับ Python (ไม่มีจุดหมาย) นี้:
"""Module for watching birds and their age."""
from dataclasses import dataclass
@ dataclass
class Bird :
"""A bird!"""
name : str
age : int
def celebrate_birthday ( self ):
print ( "?" )
self . age += 1
@ classmethod
def from_egg ( egg ):
"""Create a bird from an egg."""
pass # No bird here yet!
def register_bird ( bird : Bird , db : Db ) -> None :
assert bird . age >= 0
with db . tx () as tx :
tx . insert ( bird )
ซึ่งสามารถค้นหาได้โดยใช้:
$ cat birds.py | srgn --python ' class ' ' age '
11: age: int
15: self.age += 1
ค้นหา age
สตริงและพบ เฉพาะ ในคำจำกัดความ class
Python เท่านั้น (และไม่ใช่ในเนื้อหาของฟังก์ชันเช่น register_bird
ซึ่ง age
ก็เกิดขึ้นเช่นกันและแทบจะเป็นไปไม่ได้เลยที่จะแยกออกจากการพิจารณาใน vanilla grep
) ตามค่าเริ่มต้น 'โหมดการค้นหา' นี้จะพิมพ์หมายเลขบรรทัดด้วย โหมดการค้นหาจะถูกป้อนหากไม่มีการระบุการกระทำ และภาษาเช่น --python
จะได้รับ 1 — ให้คิดว่ามันเหมือนกับ 'ripgrep แต่มีองค์ประกอบภาษาวากยสัมพันธ์'
การค้นหาสามารถทำได้ข้ามบรรทัด เช่น ค้นหาวิธีการ (aka def
ภายใน class
) ที่ไม่มีเอกสาร:
$ cat birds.py | srgn --python ' class ' ' def .+:ns+[^"s]{3} ' # do not try this pattern at home
13: def celebrate_birthday(self):
14: print("?")
โปรดสังเกตว่าสิ่งนี้ไม่แสดง from_egg
(มี docstring) หรือ register_bird
(ไม่ใช่วิธี def
ภายนอก class
)
ขอบเขตภาษาสามารถระบุได้หลายครั้งเช่นกัน ตัวอย่างเช่น ในตัวอย่างข้อมูลของ Rust
pub enum Genre {
Rock ( Subgenre ) ,
Jazz ,
}
const MOST_POPULAR_SUBGENRE : Subgenre = Subgenre :: Something ;
pub struct Musician {
name : String ,
genres : Vec < Subgenre > ,
}
สามารถเจาะสิ่งของหลายชิ้นลงไปได้
$ cat music.rs | srgn --rust ' pub-enum ' --rust ' type-identifier ' ' Subgenre ' # AND'ed together
2: Rock(Subgenre),
โดยที่ส่งคืนเฉพาะบรรทัดที่ตรงกับเกณฑ์ ทั้งหมด โดยทำหน้าที่เสมือนตรรกะ และ อยู่ระหว่างเงื่อนไขทั้งหมด โปรดทราบว่าเงื่อนไขต่างๆ จะถูกประเมินจากซ้ายไปขวา โดยไม่รวมชุดค่าผสมบางอย่างที่ไม่สมเหตุสมผล เช่น การค้นหาเนื้อหา class
Python ภายใน doc-strings
Python มักจะไม่ส่งคืนสิ่งใดเลย การผกผันทำงานได้ตามที่คาดไว้อย่างไรก็ตาม:
$ cat birds.py | srgn --py ' class ' --py ' doc-strings '
8: """A bird!"""
19: """Create a bird from an egg."""
ไม่มีการเปิดเผยเอกสารนอกเนื้อหาของ class
!
แฟล็ก -j
จะเปลี่ยนลักษณะการทำงานนี้: ตั้งแต่การตัดกันจากซ้ายไปขวา ไปจนถึงการเรียกใช้คิวรีทั้งหมดอย่างอิสระและรวมผลลัพธ์เข้าด้วยกัน ทำให้คุณสามารถค้นหาได้หลายวิธีในคราวเดียว:
$ cat birds.py | srgn -j --python ' comments ' --python ' doc-strings ' ' bird[^s] '
8: """A bird!"""
19: """Create a bird from an egg."""
20: pass # No bird here yet!
พบรูปแบบ bird[^s]
ในความคิดเห็น หรือ เอกสารเช่นเดียวกัน ไม่ใช่แค่ "เอกสาร ภายใน ความคิดเห็น"
หากไม่ได้ระบุอินพุตมาตรฐาน srgn
จะรู้วิธีค้นหาไฟล์ต้นฉบับที่เกี่ยวข้องโดยอัตโนมัติ เช่น ในที่เก็บนี้:
$ srgn --python ' class ' ' age '
docs/samples/birds
11: age: int
15: self.age += 1
docs/samples/birds.py
9: age: int
13: self.age += 1
มันจะเดินซ้ำในไดเร็กทอรีปัจจุบัน ค้นหาไฟล์ตามนามสกุลไฟล์และบรรทัด shebang ประมวลผลด้วยความเร็วสูงมาก ตัวอย่างเช่น srgn --go strings 'd+'
ค้นหาและพิมพ์ตัวเลขทั้งหมด ~140,000 หลักในสตริง Go ตามตัวอักษรภายในฐานโค้ด Kubernetes ที่มีโค้ด Go ~3,000,000 บรรทัดภายใน 3 วินาทีบน 12 คอร์ของ M3 หากต้องการข้อมูลเพิ่มเติมเกี่ยวกับการทำงานกับไฟล์จำนวนมาก โปรดดูด้านล่าง
ขอบเขตและการดำเนินการสามารถรวมกันได้เกือบจะโดยพลการ (แม้ว่าหลายชุดจะไม่นำไปใช้หรือมีความหมายก็ตาม) ตัวอย่างเช่น ลองพิจารณาตัวอย่าง Python นี้ (เช่น ตัวอย่างการใช้ภาษาอื่นๆ ที่รองรับ ดูด้านล่าง):
"""GNU module."""
def GNU_says_moo ():
"""The GNU function -> say moo -> ✅"""
GNU = """
GNU
""" # the GNU...
print ( GNU + " says moo" ) # ...says moo
ซึ่งรันคำสั่งต่อไปนี้:
cat gnu.py | srgn --titlecase --python ' doc-strings ' ' (?' ' $1: GNU ? is not Unix '
กายวิภาคของการภาวนานั้นคือ:
--titlecase
(การกระทำ) จะเป็น Titlecase ทุกอย่างที่พบในขอบเขต
--python 'doc-strings'
(ขอบเขต) จะกำหนดขอบเขตเป็น (เช่น พิจารณาเท่านั้น) สตริงเอกสารตามไวยากรณ์ภาษา Python
'(? (ขอบเขต) เห็นเฉพาะขอบเขตที่ตัวเลือกก่อนหน้ากำหนดขอบเขตไว้แล้ว และจะจำกัดขอบเขตให้แคบลงอีก ไม่สามารถขยายขอบเขตก่อนหน้านี้ได้ ขอบเขตของนิพจน์ทั่วไปจะถูกนำไปใช้หลังขอบเขตภาษาใดๆ
(? เป็นไวยากรณ์ lookbehind เชิงลบ ซึ่งแสดงให้เห็นว่าคุณลักษณะขั้นสูงนี้พร้อมใช้งานได้อย่างไร สตริงของ
GNU
ที่นำหน้าด้วย The
จะไม่ได้รับการพิจารณา
'$1: GNU ? is not Unix'
(การกระทำ) จะ แทนที่ แต่ละรายการที่ตรงกัน (เช่น แต่ละส่วนอินพุตที่พบว่าอยู่ในขอบเขต) ด้วยสตริงนี้ เหตุการณ์ที่ตรงกันคือรูปแบบของ '(? ภายในสตริงเอกสาร Python เท่านั้น โดยเฉพาะอย่างยิ่ง สตริงการแทนที่นี้แสดงให้เห็นว่า:
$1
ซึ่งมีเนื้อหาที่บันทึกโดยกลุ่ม regex ที่จับภาพกลุ่มแรก นั่นคือ ([az]+)
เนื่องจาก (? ไม่ได้จับภาพ
คำสั่งใช้ขอบเขตหลายขอบเขต (ภาษาและรูปแบบ regex) และการดำเนินการหลายอย่าง (การแทนที่และการกำหนดชื่อเรื่อง) ผลลัพธ์จะอ่าน
"""Module: GNU ? Is Not Unix."""
def GNU_says_moo ():
"""The GNU function -> say moo -> ✅"""
GNU = """
GNU
""" # the GNU...
print ( GNU + " says moo" ) # ...says moo
โดยที่การเปลี่ยนแปลงจะจำกัดอยู่ที่:
- """GNU module."""
+ """Module: GNU ? Is Not Unix."""
def GNU_says_moo():
"""The GNU -> say moo -> ✅"""
คำเตือน
แม้ว่า srgn
จะเป็นเวอร์ชันเบต้า (เวอร์ชันหลัก 0) โปรดตรวจสอบให้แน่ใจว่าได้ประมวลผลเฉพาะไฟล์ (แบบเรียกซ้ำ) ที่คุณสามารถกู้คืนได้อย่างปลอดภัย
โหมดการค้นหาจะไม่เขียนทับไฟล์ ดังนั้นจึงปลอดภัยเสมอ
ดูด้านล่างสำหรับผลลัพธ์ความช่วยเหลือทั้งหมดของเครื่องมือ
บันทึก
ภาษาที่รองรับได้แก่
ดาวน์โหลดไบนารีที่สร้างไว้ล่วงหน้าจากรุ่นต่างๆ
ลังนี้จัดเตรียมไบนารีในรูปแบบที่เข้ากันได้กับ cargo-binstall
:
cargo install cargo-binstall
(อาจใช้เวลาสักครู่)cargo binstall srgn
(สองสามวินาทีในขณะที่ดาวน์โหลดไบนารีที่สร้างไว้ล่วงหน้าจาก GitHub)ขั้นตอนเหล่านี้รับประกันว่าจะได้ผล™ เนื่องจากมีการทดสอบใน CI นอกจากนี้ยังใช้งานได้หากไม่มีไบนารีที่สร้างไว้ล่วงหน้าสำหรับแพลตฟอร์มของคุณ เนื่องจากเครื่องมือจะถอยกลับไปเป็นการคอมไพล์จากแหล่งที่มา
สามารถหาสูตรได้ทาง:
brew install srgn
ใช้งานได้ผ่านความไม่เสถียร:
nix-shell -p srgn
มีจำหน่ายผ่านทาง AUR
มีพอร์ตให้เลือก:
sudo port install srgn
อิมเมจนักวิ่ง GitHub Actions ทั้งหมดมาพร้อมกับ cargo
ที่ติดตั้งไว้ล่วงหน้า และ cargo-binstall
มอบ GitHub Action ที่สะดวกสบาย:
jobs :
srgn :
name : Install srgn in CI
# All three major OSes work
runs-on : ubuntu-latest
steps :
- uses : cargo-bins/cargo-binstall@main
- name : Install binary
run : >
cargo binstall
--no-confirm
srgn
- name : Use binary
run : srgn --version
ข้างต้นจะสรุปในเวลาเพียง 5 วินาทีเท่านั้น เนื่องจากไม่จำเป็นต้องคอมไพล์ สำหรับบริบทเพิ่มเติม โปรดดูคำแนะนำของ cargo-binstall
เกี่ยวกับ CI
บน Linux gcc
ใช้งานได้
บน macOS ให้ใช้ clang
.
บน Windows MSVC ใช้งานได้
เลือก "การพัฒนาเดสก์ท็อปด้วย C++" ในการติดตั้ง
cargo install srgn
cargo add srgn
ดูที่นี่เพิ่มเติม
รองรับเชลล์ต่างๆ สำหรับสคริปต์การเติมเชลล์ให้สมบูรณ์ ตัวอย่างเช่น ผนวก eval "$(srgn --completions zsh)"
ต่อท้าย ~/.zshrc
เพื่อความสมบูรณ์ใน ZSH เซสชันแบบโต้ตอบสามารถมีลักษณะดังนี้:
เครื่องมือนี้ได้รับการออกแบบตาม ขอบเขต และ การดำเนินการ ขอบเขตทำให้ส่วนของอินพุตที่จะประมวลผลแคบลง การดำเนินการจะดำเนินการประมวลผล โดยทั่วไป ทั้งขอบเขตและการดำเนินการสามารถประกอบกันได้ ดังนั้นจึงอาจส่งผ่านมากกว่าหนึ่งรายการได้ ทั้งสองเป็นทางเลือก (แต่การไม่ดำเนินการใด ๆ นั้นไม่มีประโยชน์) การไม่ระบุขอบเขตแสดงว่าอินพุตทั้งหมดอยู่ในขอบเขต
ในเวลาเดียวกัน มีการทับซ้อนกันอย่างมากกับ tr
ธรรมดา : เครื่องมือนี้ได้รับการออกแบบมาให้มีความสอดคล้องกันอย่างใกล้ชิดในกรณีการใช้งานที่พบบ่อยที่สุด และจะไปไกลกว่านั้นเมื่อจำเป็นเท่านั้น
การดำเนินการที่ง่ายที่สุดคือการทดแทน มีการเข้าถึงเป็นพิเศษ (เป็นอาร์กิวเมนต์ ไม่ใช่ตัวเลือก) เพื่อความเข้ากันได้กับ tr
และการยศาสตร์ทั่วไป การดำเนินการอื่นๆ ทั้งหมดจะได้รับเป็นแฟล็ก หรือตัวเลือกที่ควรได้รับค่า
ตัวอย่างเช่น การแทนที่แบบอักขระเดียวอย่างง่ายจะทำงานเหมือนกับใน tr
:
$ echo ' Hello, World! ' | srgn ' H ' ' J '
Jello, World!
อาร์กิวเมนต์แรกคือขอบเขต (ตัวอักษร H
ในกรณีนี้) สิ่งใดก็ตามที่จับคู่จะถูกประมวลผล (แทนที่ด้วย J
อาร์กิวเมนต์ที่สองในกรณีนี้) อย่างไรก็ตาม ไม่มีแนวคิดโดยตรงเกี่ยวกับคลาสอักขระ เช่นเดียวกับใน tr
โดยค่าเริ่มต้น ขอบเขตจะเป็นรูปแบบนิพจน์ทั่วไป ดังนั้นคลาส ของขอบเขต จึงสามารถใช้เพื่อให้เอฟเฟกต์คล้ายกันได้:
$ echo ' Hello, World! ' | srgn ' [a-z] ' ' _ '
H____, W____!
การแทนที่เกิดขึ้นอย่างตะกละตะกลามตลอดการแข่งขันทั้งหมดโดยค่าเริ่มต้น (สังเกตคลาสอักขระ UTS ซึ่งชวนให้นึกถึง tr
's [:alnum:]
):
$ echo ' ghp_oHn0As3cr3T!! ' | srgn ' ghp_[[:alnum:]]+ ' ' * ' # A GitHub token
*!!
รองรับฟีเจอร์ regex ขั้นสูง เช่น การมองรอบๆ:
$ echo ' ghp_oHn0As3cr3T ' | srgn ' (?<=ghp_)[[:alnum:]]+ ' ' * '
ghp_*
ระมัดระวังในการใช้สิ่งเหล่านี้อย่างปลอดภัย เนื่องจากรูปแบบขั้นสูงมาโดยไม่มีการรับประกันความปลอดภัยและประสิทธิภาพที่แน่นอน หากไม่ได้ใช้ ประสิทธิภาพจะไม่ได้รับผลกระทบ
การแทนที่ไม่จำกัดเพียงอักขระตัวเดียว อาจเป็นสตริงใดก็ได้ เช่น เพื่อแก้ไขเครื่องหมายคำพูดนี้:
$ echo ' "Using regex, I now have no issues." ' | srgn ' no issues ' ' 2 problems '
"Using regex, I now have 2 problems."
เครื่องมือนี้รับรู้ถึง Unicode โดยสมบูรณ์ พร้อมการสนับสนุนที่เป็นประโยชน์สำหรับคลาสอักขระขั้นสูงบางคลาส:
$ echo ' Mood: ? ' | srgn ' ? ' ' ? '
Mood: ?
$ echo ' Mood: ???? :( ' | srgn ' p{Emoji_Presentation} ' ' ? '
Mood: ???? :(
การแทนที่จะรับรู้ถึงตัวแปร ซึ่งทำให้สามารถเข้าถึงได้เพื่อใช้ผ่านกลุ่มการบันทึก regex กลุ่มแคปเจอร์สามารถกำหนดหมายเลขหรือตั้งชื่อก็ได้ กลุ่มการจับที่ศูนย์สอดคล้องกับการแข่งขันทั้งหมด
$ echo ' Swap It ' | srgn ' (w+) (w+) ' ' $2 $1 ' # Regular, numbered
It Swap
$ echo ' Swap It ' | srgn ' (w+) (w+) ' ' $2 $1$1$1 ' # Use as many times as you'd like
It SwapSwapSwap
$ echo ' Call +1-206-555-0100! ' | srgn ' Call (+?d-d{3}-d{3}-d{4}).+ ' ' The phone number in "$0" is: $1. ' # Variable `0` is the entire match
The phone number in "Call +1-206-555-0100!" is: +1-206-555-0100.
กรณีการใช้งานขั้นสูงกว่านั้น เช่น การปรับโครงสร้างโค้ดใหม่โดยใช้กลุ่มแคปเจอร์ที่มีชื่อ (บางทีคุณอาจได้สิ่งที่มีประโยชน์มากกว่า...):
$ echo ' let x = 3; ' | srgn ' let (?[a-z]+) = (?.+); ' ' const $var$var = $expr + $expr; '
const xx = 3 + 3;
เช่นเดียวกับใน bash ให้ใช้เครื่องหมายปีกกาเพื่อแยกตัวแปรออกจากเนื้อหาที่อยู่ติดกัน:
$ echo ' 12 ' | srgn ' (d)(d) ' ' $2${1}1 '
211
$ echo ' 12 ' | srgn ' (d)(d) ' ' $2$11 ' # will fail (`11` is unknown)
$ echo ' 12 ' | srgn ' (d)(d) ' ' $2${11 ' # will fail (brace was not closed)
เมื่อเห็นว่าการแทนที่เป็นเพียงสตริงแบบสแตติก ประโยชน์ของมันก็มีจำกัด นี่คือจุดที่ซอสสูตรลับของ tr
มักเข้ามามีบทบาท: การใช้คลาสอักขระซึ่งใช้ได้ในตำแหน่งที่สองเช่นกัน โดยแปลจากสมาชิกของตัวแรกไปที่สองอย่างเรียบร้อย ที่นี่คลาสเหล่านั้นแทนที่จะเป็น regexes และใช้ได้เฉพาะในตำแหน่งแรก (ขอบเขต) นิพจน์ทั่วไปที่เป็นเครื่องสถานะ จึงเป็นไปไม่ได้ที่จะจับคู่กับ 'รายการอักขระ' ซึ่งใน tr
คืออาร์กิวเมนต์ที่สอง (เป็นทางเลือก) แนวคิดนั้นอยู่นอกหน้าต่าง และความยืดหยุ่นก็สูญเสียไป
แต่จะใช้การดำเนินการที่นำเสนอซึ่งทั้งหมด ได้รับการแก้ไขแล้ว แทน การดูกรณีการใช้งานที่พบบ่อยที่สุดสำหรับ tr
เผยให้เห็นว่าชุดการดำเนินการที่ให้มานั้นครอบคลุมเกือบทั้งหมด! คุณสามารถแจ้งปัญหาได้หากไม่ครอบคลุมกรณีการใช้งานของคุณ
ไปสู่การดำเนินการครั้งต่อไป
ลบสิ่งที่พบออกจากอินพุต ชื่อแฟล็กเดียวกับใน tr
$ echo ' Hello, World! ' | srgn -d ' (H|W|!) '
ello, orld
บันทึก
เนื่องจากขอบเขตเริ่มต้นจะตรงกับอินพุตทั้งหมด การระบุการลบโดยไม่มีขอบเขตจึงเป็นข้อผิดพลาด
บีบการซ้ำของอักขระที่ตรงกับขอบเขตให้เป็นเหตุการณ์เดียว ชื่อแฟล็กเดียวกับใน tr
$ echo ' Helloooo Woooorld!!! ' | srgn -s ' (o|!) '
Hello World!
หากคลาสตัวละครผ่านไป สมาชิกทั้งหมดของคลาสนั้นจะถูกบีบให้เข้าคลาสที่สมาชิกคลาสใดพบเจอก่อน:
$ echo ' The number is: 3490834 ' | srgn -s ' d '
The number is: 3
ความโลภในการจับคู่ไม่ได้รับการแก้ไข ดังนั้นโปรดระวัง:
$ echo ' Winter is coming... ??? ' | srgn -s ' ?+ '
Winter is coming... ???
บันทึก
รูปแบบตรงกับดวงอาทิตย์ ทั้งหมด ดังนั้นจึงไม่มีอะไรต้องบีบ ฤดูร้อนมีชัย
สลับความโลภหากกรณีการใช้งานเรียกร้อง:
$ echo ' Winter is coming... ??? ' | srgn -s ' ?+? ' ' ☃️ '
Winter is coming... ☃️
บันทึก
เช่นเดียวกับการลบ การระบุการบีบโดยไม่มีขอบเขต ที่ชัดเจน ถือเป็นข้อผิดพลาด มิฉะนั้นอินพุตทั้งหมดจะถูกบีบ
การใช้งาน tr
ส่วนที่ดีอยู่ในหมวดหมู่นี้ มันตรงไปตรงมามาก
$ echo ' Hello, World! ' | srgn --lower
hello, world!
$ echo ' Hello, World! ' | srgn --upper
HELLO, WORLD!
$ echo ' hello, world! ' | srgn --titlecase
Hello, World!
แยกย่อยอินพุตตามแบบฟอร์มการทำให้เป็นมาตรฐาน D จากนั้นละทิ้งจุดโค้ดของหมวดหมู่ Mark (ดูตัวอย่าง) นั่นหมายความว่า: ใช้ตัวละครแฟนซี ฉีกสิ่งที่ห้อยต่องแต่งออก และโยนสิ่งเหล่านั้นทิ้งไป
$ echo ' Naïve jalapeño ärgert mgła ' | srgn -d ' P{ASCII} ' # Naive approach
Nave jalapeo rgert mga
$ echo ' Naïve jalapeño ärgert mgła ' | srgn --normalize # Normalize is smarter
Naive jalapeno argert mgła
สังเกตว่า mgła
อยู่นอกขอบเขตของ NFD อย่างไร เนื่องจากเป็น "อะตอมมิก" และไม่สามารถย่อยสลายได้ (อย่างน้อยนั่นคือสิ่งที่ ChatGPT กระซิบข้างหูของฉัน)
การดำเนินการนี้จะแทนที่สัญลักษณ์ ASCII แบบหลายอักขระด้วยจุดรหัสเดียวที่เหมาะสม ซึ่งเป็นคู่กันของ Unicode ดั้งเดิม
$ echo ' (A --> B) != C --- obviously ' | srgn --symbols
(A ⟶ B) ≠ C — obviously
หรือหากคุณสนใจเฉพาะวิชาคณิตศาสตร์ ให้ใช้การกำหนดขอบเขต:
$ echo ' A <= B --- More is--obviously--possible ' | srgn --symbols ' <= '
A ≤ B --- More is--obviously--possible
เนื่องจากมีความสอดคล้องกันในอัตราส่วน 1:1 ระหว่างสัญลักษณ์ ASCII และการแทนที่ เอฟเฟกต์จึงสามารถย้อนกลับได้ 2 :
$ echo ' A ⇒ B ' | srgn --symbols --invert
A => B
ขณะนี้มีชุดสัญลักษณ์ที่รองรับจำนวนจำกัด แต่สามารถเพิ่มได้อีก
การดำเนินการนี้จะแทนที่การสะกดทางเลือกของอักขระพิเศษภาษาเยอรมัน (ae, oe, ue, ss) ด้วยเวอร์ชันดั้งเดิม (ä, ö, ü, ß) 3
$ echo ' Gruess Gott, Neueroeffnungen, Poeten und Abenteuergruetze! ' | srgn --german
Grüß Gott, Neueröffnungen, Poeten und Abenteuergrütze!
การดำเนินการนี้อิงตามรายการคำ (คอมไพล์โดยไม่มีฟีเจอร์ german
หากสิ่งนี้ทำให้ไบนารี่ของคุณขยายมากเกินไป) สังเกตคุณสมบัติต่อไปนี้เกี่ยวกับตัวอย่างข้างต้น:
Poeten
ยังคงเหมือนเดิม แทนที่จะถูกแปลงเป็น Pöten
อย่างไร้เดียงสาและผิดพลาดAbenteuergrütze
จะไม่พบในรายการคำที่สมเหตุสมผลใด ๆ แต่ได้รับการจัดการอย่างเหมาะสมอย่างไรก็ตามAbenteuer
ยังคงอยู่เหมือนเดิม แทนที่จะแปลงเป็น Abenteür
อย่างไม่ถูกต้องNeueroeffnungen
แอบสร้างองค์ประกอบ ue
ที่ไม่มีคำที่เป็นส่วนประกอบ ( neu
, Eröffnungen
) ครอบครอง แต่ยังคงประมวลผลอย่างถูกต้อง (แม้จะมีปลอกที่ไม่ตรงกันเช่นกัน)เมื่อมีการร้องขอ อาจบังคับให้มีการเปลี่ยนทดแทน ซึ่งอาจเป็นประโยชน์สำหรับชื่อ:
$ echo ' Frau Loetter steht ueber der Mauer. ' | srgn --german-naive ' (?<=Frau )w+ '
Frau Lötter steht ueber der Mauer.
ด้วยการมองไปข้างหน้าเชิงบวก ไม่มีอะไรนอกจากคำทักทายที่ถูกจำกัดขอบเขตและดังนั้นจึงมีการเปลี่ยนแปลง Mauer
ยังคงเหมือนเดิมอย่างถูกต้อง แต่ ueber
ไม่ได้รับการประมวลผล การส่งผ่านครั้งที่สองจะแก้ไขสิ่งนี้:
$ echo ' Frau Loetter steht ueber der Mauer. ' | srgn --german-naive ' (?<=Frau )w+ ' | srgn --german
Frau Lötter steht über der Mauer.
บันทึก
ตัวเลือกและแฟล็กที่เกี่ยวข้องกับ "พาเรนต์" บางตัวจะขึ้นหน้าด้วยชื่อของพาเรนต์ และจะ สื่อถึง พาเรนต์เมื่อได้รับ ในลักษณะที่ไม่จำเป็นต้องส่งค่าหลังอย่างชัดเจน นั่นเป็นสาเหตุที่ --german-naive
ได้รับการตั้งชื่อตามที่เป็นอยู่ และ --german
ไม่จำเป็นต้องผ่าน
ลักษณะการทำงานนี้อาจเปลี่ยนแปลงได้เมื่อ clap
รองรับการผูกมัดคำสั่งย่อย
บางสาขาไม่สามารถตัดสินใจได้สำหรับเครื่องมือที่เรียบง่ายนี้ เนื่องจากทำงานโดยไม่มีบริบททางภาษา ตัวอย่างเช่น ทั้ง Busse
(busses) และ Buße
(ปลงอาบัติ) เป็นคำทางกฎหมาย ตามค่าเริ่มต้น การแทนที่จะดำเนินการอย่างตะกละตะกลามหากถูกกฎหมาย (นั่นคือจุดรวมของ srgn
ท้ายที่สุด) แต่มีการตั้งค่าสถานะสำหรับการสลับพฤติกรรมนี้:
$ echo ' Busse und Geluebte ' | srgn --german
Buße und Gelübte
$ echo ' Busse ? und Fussgaenger ?♀️ ' | srgn --german-prefer-original
Busse ? und Fußgänger ?♀️
การดำเนินการส่วนใหญ่เป็นแบบเรียบเรียงได้ เว้นแต่การกระทำดังกล่าวจะไร้สาระ (เช่น การลบ) ลำดับการสมัครได้รับการแก้ไขแล้ว ดังนั้น ลำดับ ของแฟล็กที่ให้มาจึงไม่มีอิทธิพล (การรันหลาย ๆ ไพพ์เป็นอีกทางเลือกหนึ่ง หากจำเป็น) การเปลี่ยนเกิดขึ้นก่อนเสมอ โดยทั่วไป CLI ได้รับการออกแบบมาเพื่อป้องกันการใช้งานในทางที่ผิดและความประหลาดใจ โดยชอบที่จะหยุดทำงานมากกว่าทำสิ่งที่ไม่คาดคิด (ซึ่งแน่นอนว่าเป็นเรื่องส่วนตัว) โปรดทราบว่าการผสมผสานหลายๆ อย่าง เป็น ไปได้ในทางเทคนิค แต่อาจให้ผลลัพธ์ที่ไม่สมเหตุสมผล
การดำเนินการแบบผสมผสานอาจมีลักษณะดังนี้:
$ echo ' Koeffizienten != Bruecken... ' | srgn -Sgu
KOEFFIZIENTEN ≠ BRÜCKEN...
คุณสามารถระบุขอบเขตที่แคบกว่านี้ได้ และจะนำไปใช้กับการดำเนินการ ทั้งหมด อย่างเท่าเทียมกัน:
$ echo ' Koeffizienten != Bruecken... ' | srgn -Sgu ' bw{1,8}b '
Koeffizienten != BRÜCKEN...
จำเป็นต้องมีขอบเขตของคำ มิฉะนั้น Koeffizienten
จะจับคู่กับ Koeffizi
และ enten
สังเกตว่าช่วงต่อท้ายไม่สามารถถูกบีบได้ เช่น อย่างไร ขอบเขตที่ต้องการของ .
จะรบกวนสิ่งที่ได้รับ การวางท่อแบบปกติจะช่วยแก้ปัญหานี้ได้:
$ echo ' Koeffizienten != Bruecken... ' | srgn -Sgu ' bw{1,8}b ' | srgn -s ' . '
Koeffizienten != BRÜCKEN.
หมายเหตุ: การหลีกเลี่ยง regex ( .
) สามารถหลีกเลี่ยงได้โดยใช้การกำหนดขอบเขตตามตัวอักษร การดำเนินการเปลี่ยนที่ได้รับการดูแลเป็นพิเศษยังสามารถประกอบได้:
$ echo ' Mooood: ????!!! ' | srgn -s ' p{Emoji} ' ' ? '
Mooood: ?!!!
ขั้นแรกอิโมจิจะถูกแทนที่ทั้งหมด จากนั้นจึงบีบ สังเกตว่าไม่มีอะไรถูกบีบอีกเลย
ขอบเขตเป็นแนวคิดในการขับขี่ลำดับที่สองของ srgn
ในกรณีเริ่มต้น ขอบเขตหลักคือนิพจน์ทั่วไป ส่วนการดำเนินการแสดงกรณีการใช้งานนี้โดยละเอียด ดังนั้นจึงไม่มีการทำซ้ำที่นี่ มันถูกกำหนดให้เป็นอาร์กิวเมนต์ตำแหน่งแรก
srgn
ขยายขอบเขตนี้ผ่านขอบเขตการรับรู้ไวยากรณ์ภาษาที่เตรียมไว้ ซึ่งเกิดขึ้นได้ผ่านไลบรารี tree-sitter
ที่ยอดเยี่ยม มีคุณลักษณะการสืบค้น ซึ่งทำงานเหมือนกับการจับคู่รูปแบบกับโครงสร้างข้อมูลแบบต้นไม้
srgn
มาพร้อมกับข้อความค้นหาเหล่านี้ที่มีประโยชน์ที่สุดจำนวนหนึ่ง ผ่าน API ที่ค้นพบได้ (ไม่ว่าจะเป็นห้องสมุดหรือผ่าน CLI, srgn --help
) เราสามารถเรียนรู้เกี่ยวกับภาษาที่รองรับและแบบสอบถามที่เตรียมไว้ แต่ละภาษาที่รองรับมาพร้อมกับ Escape Hatch ช่วยให้คุณสามารถเรียกใช้คำสั่งเฉพาะกิจของคุณเองได้ ฟักมาในรูปแบบของ --lang-query
โดยที่ lang
เป็นภาษาเช่น python
ดูด้านล่างสำหรับข้อมูลเพิ่มเติมเกี่ยวกับหัวข้อขั้นสูงนี้
บันทึก
ขอบเขตภาษาจะถูกใช้ ก่อน ดังนั้นไม่ว่าคุณจะผ่านขอบเขตหลักหรือที่เรียกว่า regex ใดก็ตาม ขอบเขตภาษานั้นจะทำงานในโครงสร้างภาษาที่ตรงกันแต่ละรายการแยกกัน
ส่วนนี้จะแสดงตัวอย่างสำหรับ การสืบค้นที่เตรียมไว้ บางส่วน
unsafe
ทั้งหมด (สนิม) ข้อดีอย่างหนึ่งของคีย์เวิร์ด unsafe
ใน Rust ก็คือ "ความสามารถในการใช้งานได้" อย่างไรก็ตาม rg 'unsafe'
จะแสดงการจับคู่สตริง ทั้งหมด อย่างแน่นอน ( rg 'bunsafeb'
ช่วยได้ในระดับหนึ่ง) ไม่ใช่แค่รายการที่อยู่ในคีย์เวิร์ดภาษา Rust จริงเท่านั้น srgn
ช่วยทำให้สิ่งนี้แม่นยำยิ่งขึ้น ตัวอย่างเช่น:
// Oh no, an unsafe module!
mod scary_unsafe_operations {
pub unsafe fn unsafe_array_access ( arr : & [ i32 ] , index : usize ) -> i32 {
// UNSAFE: This function performs unsafe array access without bounds checking
* arr . get_unchecked ( index )
}
pub fn call_unsafe_function ( ) {
let unsafe_numbers = vec ! [ 1 , 2 , 3 , 4 , 5 ] ;
println ! ( "About to perform an unsafe operation!" ) ;
let result = unsafe {
// Calling an unsafe function
unsafe_array_access ( & unsafe_numbers , 10 )
} ;
println ! ( "Result of unsafe operation: {}" , result ) ;
}
}
สามารถค้นหาได้เป็น