ทำไม '[az] *' ตรงกับสตริงที่ไม่ใช่ตัวอักษร?


9

ฉันมีไฟล์ที่alphanumมีสองบรรทัดเหล่านี้:

123 abc
this is a line

ฉันสับสนว่าทำไมเมื่อฉันรันsed 's/[a-z]*/SUB/' alphanumฉันจะได้ผลลัพธ์ต่อไปนี้:

SUB123 abc
SUB is a line

ผมคาดหวังว่า:

123 SUB
SUB is a line

ฉันพบวิธีแก้ไข (ใช้sed 's/[a-z][a-z]*/SUB/'แทน) แต่ฉันไม่เข้าใจว่าทำไมมันถึงใช้งานได้และของฉันก็ใช้ไม่ได้

คุณช่วยได้ไหม



@Kamaraj คนนั้นคล้ายกัน แต่มีรูปแบบของเชลล์เทียบกับความสับสนด้านบน regexes (และคำตอบนั้นให้ความสนใจกับอดีตเพราะนั่นคือสิ่งที่ls foo*ใช้) แต่อย่างไรก็ตามหากคุณพบคำถามที่ซ้ำซ้อนฉันคิดว่าคุณควรติดธงทำเครื่องหมายเช่นนั้นด้วย
ilkkachu

ตรวจสอบregexr.comสำหรับภาพสด & อธิบาย
RozzA

@RozzA โปรดทราบว่าเว็บไซต์ที่คุณเชื่อมโยงเพื่อรองรับการแสดงผลปกติของ Javascript และ Perl ไม่ใช่การแสดงออกปกติ POSIX
Kusalananda

คำตอบ:


28

รูปแบบ[a-z]*จับคู่อักขระศูนย์หรือมากกว่าในช่วงaถึงz( อักขระจริงขึ้นอยู่กับสถานที่ปัจจุบัน) มีศูนย์ตัวละครดังกล่าวที่เริ่มต้นมากของสตริงที่มี123 abc(เช่นการแข่งขันรูปแบบ) this is a lineและสี่ของพวกเขาในช่วงเริ่มต้นของ

หากคุณต้องไม่น้อยกว่าหนึ่งในการแข่งขันแล้วใช้[a-z][a-z]*หรือ[a-z]\{1,\}หรือใช้การแสดงออกปกติขยายและการใช้งานsed -E[a-z]+

หากต้องการให้เห็นภาพของรูปแบบที่ตรงกันให้เพิ่มวงเล็บในแต่ละคู่ที่ตรงกัน:

$ sed 's/[a-z]*/(&)/' file
()123 abc
(this) is a line

หรือเพื่อดูการแข่งขันทั้งหมดในบรรทัด:

$ sed 's/[a-z]*/(&)/g' file
()1()2()3() (abc)
(this) (is) (a) (line)

เปรียบเทียบผลลัพธ์สุดท้ายกับ

$ sed -E 's/[a-z]+/(&)/g' file
123 (abc)
(this) (is) (a) (line)

7
ในทางเทคนิค[a-z]ตรงกับองค์ประกอบการเรียงซึ่งสามารถทำได้มากกว่าหนึ่งตัวอักษร ตัวอย่างเช่นในบางพื้นที่ของฮังการี[a-z]ตรงกับdzs
Stéphane Chazelas

12

เนื่องจาก*ตรงกับการซ้ำซ้อนของอะตอมก่อนหน้าเป็นศูนย์หรือมากกว่าและเอ็นจิน regex ทั้งหมดพยายามหาคู่แรก มีสตริงย่อยของตัวอักษรเป็นศูนย์ในการเริ่มต้นของสตริงของคุณดังนั้นมันจึงตรงกับที่ ในกรณีที่สตริงเริ่มต้นด้วยตัวอักษรการ*จับคู่ให้มากที่สุดเท่าที่จะทำได้ แต่นี่เป็นเรื่องรองสำหรับการค้นหาการจับคู่ซ้ายสุด

การจับคู่แบบไม่มีความยาวอาจเป็นปัญหาเล็กน้อยและอย่างที่คุณเห็นวิธีแก้ไขคือการปรับเปลี่ยนรูปแบบเพื่อให้ต้องใช้อักขระอย่างน้อยหนึ่งตัว ด้วย regex แบบขยายคุณสามารถทำได้+ดังนี้:sed -E 's/[a-z]+/SUB/'

เพื่อความสนุกสนานลอง:

echo 'less than 123 words' | sed 's/[0-9]*/x/g'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.