ทำไมฉันต้องหลบหนีอักขระ regex ใน sed เพื่อตีความว่าเป็นอักขระ regex


11

ดูเหมือน
cat sed_data.txt | sed 's/\b[0-9]\{3\}\b/NUMBER/g'
ว่าฉันจะต้องหลบหนีตัวละครเพื่อสร้างการแสดงออกปกติ ในกรณีนี้ฉันต้องหลบหนีเครื่องมือจัดฟันเพื่อที่จะตีความได้หลายครั้ง
ทำไม? ฉันคาดหวังว่าทุกอย่างจะเป็นตัวละคร regex เว้นแต่จะหลบหนี นั่นคือสิ่งที่ตรงกันข้าม


มีการโพสต์เกี่ยวกับการค้นหาในกลุ่มที่ค่อนข้างครอบคลุมคำถามนี้รุ่นสั้น ๆ คือ "มันขึ้นอยู่กับการใช้งานคำสั่ง" ... unix.stackexchange.com/questions/90345/…
Drav Sloan

@DravSloan: ผมไม่แน่ใจว่ามันเป็น same.In เป็นกลุ่มที่คุณค้นหาข้อความโดยค่าเริ่มต้นและคุณจำเป็นต้องหลบหนีไปค้นหา regex.But ในกรณีนี้รูปแบบs/regex//gแล้วคาดว่านิพจน์ทั่วไปและผมจะคาดหวังว่ามันเป็นข้อความที่จะต้อง ที่จะหลบหนี
จิม

คำตอบ:


14

นี่เป็นเพราะsedใช้POSIX BREs (นิพจน์ปกติพื้นฐาน) ซึ่งตรงข้ามกับ EREs (Extended Regular Expression) ที่คุณอาจเคยใช้จาก Perl หรือเพื่อน

จากsed(1)หน้าคน:

REGULAR EXPRESSIONS
       POSIX.2 BREs should be supported, but they aren't completely because of
       performance problems.  The \n sequence in a regular expression  matches
       the newline character, and similarly for \a, \t, and other sequences.

ข้อความที่เกี่ยวข้องจากลิงค์ด้านบน:

Basic Regular Expressions หรือ BREES ทำให้ได้กลิ่นรสที่คล้ายคลึงกับมาตรฐานที่ใช้โดยคำสั่ง UNIX grep แบบดั้งเดิม นี่คือรสชาติการแสดงออกปกติที่เก่าแก่ที่สุดที่ยังคงใช้อยู่ในปัจจุบัน สิ่งหนึ่งที่ทำให้รสชาตินี้แตกต่างคือเมตาบอเรเตอร์ส่วนใหญ่ต้องการแบ็กสแลชเพื่อให้รสชาติของเมตาอักขระ รสชาติอื่น ๆ ส่วนใหญ่รวมถึง POSIX ERE ใช้แบ็กสแลชเพื่อระงับความหมายของเมตาอักขระ

อ้างถึงคำต่อคำทั้งหมดจากความคิดเห็นของ Craig Sanders :

โปรดทราบว่าอย่างน้อยที่สุดใน GNU คุณสามารถบอกได้ว่าให้ใช้ regexps แบบขยายด้วยตัวเลือกบรรทัดคำสั่ง -r หรือ --regexp-Extended สิ่งนี้มีประโยชน์หากคุณต้องการหลีกเลี่ยงการทำให้สคริปต์เกลี้ยกล่อมของคุณมีการหลบหนีมากเกินไป


1
โปรดทราบว่าใน GNU sed อย่างน้อยคุณสามารถบอก sed เพื่อใช้ regexps แบบขยายด้วยตัวเลือก-rหรือ--regexp-extendedcommand line สิ่งนี้มีประโยชน์หากคุณต้องการหลีกเลี่ยงการทำให้สคริปต์เกลี้ยกล่อมของคุณมีการหลบหนีมากเกินไป
cas

@ CraigSanders ขอบคุณสำหรับสิ่งนี้ เพิ่มเพื่อตอบ
โจเซฟอาร์

@ CraigSanders sedการใช้งานอื่น ๆ(เมื่อพวกเขาสนับสนุน EREs ส่วนใหญ่ BSDs) มีแนวโน้มที่จะใช้-Eแทน (ซึ่งทำให้รู้สึกมากขึ้นเนื่องจากเป็นตัวเลือกเดียวกันgrepเพราะทำไม GNU sedเลือก-rเป็นปริศนาสำหรับฉัน)
Stéphane Chazelas

ใช่เป็นความลึกลับสำหรับฉันเช่นกัน มันจะสมเหตุสมผลมากกว่าหากใช้ -E จากนั้นเพิ่ม -F, -G และ -P เพื่อจับคู่ GNU grep IMO gawk จะได้รับประโยชน์จาก RE อันเดียวกันเช่นกัน ... หรืออย่างน้อย -P
cas

12

นั่นคือเหตุผลทางประวัติศาสตร์

Regexp เปิดตัวครั้งแรกใน Unix ในedยูทิลิตี้ในช่วงต้นยุค 70 แม้ว่าจะedอยู่บนพื้นฐานqedที่มีการดำเนินการโดยผู้เขียนเดียวกันเข้าใจ regexp ที่ซับซ้อนมากขึ้นedเท่านั้นเข้าใจ^, $, [...], ., *และ\จะหลบหนีทั้งหมดข้างต้น

ตอนนี้เมื่อจำเป็นต้องมีตัวดำเนินการเพิ่มขึ้นต้องหาวิธีที่จะแนะนำตัวดำเนินการเหล่านั้นโดยไม่ทำลายความเข้ากันได้แบบย้อนหลัง หากสคริปต์ที่ใช้ในการใช้s edคำสั่งs/foo() {/foo (var) {/gเพื่อแทนที่อินสแตนซ์ทั้งหมดfoo() {ด้วยfoo(var) { และคุณได้แนะนำตัวดำเนินการ(หรือ{ตัวดำเนินการนั่นจะทำให้สคริปต์นั้นพัง

อย่างไรก็ตามไม่มีสคริปต์ที่จะทำs/foo\(\) {/foo\(var\) {/เพราะนั่นเป็นสิ่งเดียวกันs/foo() {/foo(var) {/และไม่มีเหตุผลที่จะหลบหนี(เพราะนั่นไม่ใช่ตัวดำเนินการ RE ดังนั้นการแนะนำตัวใหม่\(หรือ\{โอเปอเรเตอร์จะไม่ทำลายความเข้ากันได้แบบย้อนหลังเนื่องจากมันไม่น่าจะทำลายสคริปต์ที่มีอยู่โดยใช้ไวยากรณ์ที่เก่ากว่า

นั่นคือสิ่งที่ทำ ต่อมา\(...\)ถูกเพิ่มเข้ามาในตอนแรกเท่านั้นสำหรับs edคำสั่งให้ทำสิ่งต่าง ๆ เช่นs/foo\(.\)/\1bar/และในภายหลังเป็นgrep '\(.\)\1'(แต่ไม่ใช่สิ่งที่ต้องการ\(xx\)*)

ใน UnixV7 (1979 เกือบทศวรรษต่อมา) รูปแบบใหม่ของการแสดงออกปกติถูกเพิ่มเข้ามาในรูปแบบใหม่egrepและawkยูทิลิตี้ที่เรียกว่าการแสดงออกปกติเพิ่มเติม (เนื่องจากเป็นเครื่องมือใหม่ไม่มีความเข้ากันได้แบบย้อนกลับ) ในที่สุดมันก็มาพร้อมกับฟังก์ชั่นที่มีอยู่ใน Ken Thompson ของโบราณqed(ตัวดำเนินการสำรอง|, การจัดกลุ่ม(..)*) และเพิ่มตัวดำเนินการบางอย่างที่ชอบ+และ?(แต่ไม่มีคุณสมบัติ backref ของการแสดงออกปกติพื้นฐาน)

ภายหลัง BSDs เพิ่ม\<และ\>(ทั้ง BRE และ ERE) และ SysV เพิ่ม\{และ\}BREs เท่านั้น

มันไม่ได้ช้าไปกว่า{และ}ถูกเพิ่มเข้าใน ERE ด้วยการใช้งานร่วมกันได้แบบย้อนกลับ ไม่ใช่ทุกคนที่เพิ่มเข้าไป ตัวอย่างเช่น GNU awkจนถึงรุ่น 4.0.0 (2011) ไม่รองรับ{เว้นแต่จะถูกบังคับให้เข้าสู่โหมดความสอดคล้อง POSIX

เมื่อ GNU grepเขียนขึ้นในช่วงต้นยุค 90 มันเพิ่มสารพัดทั้งหมดจากทั้ง BSD และ SysV (เช่น\<, {) และแทนที่จะมีไวยากรณ์ regexp สองอันแยกต่างหากและเอ็นจิ้นสำหรับ BRE และ ERE ดำเนินการตัวดำเนินการเดียวกันทั้งคู่เท่านั้น(, ?, {, +ต้องนำหน้าด้วยเครื่องหมายทับขวา (จะเข้ากันได้กับการใช้งานอื่น ๆ BRE) นั่นเป็นเหตุผลที่คุณสามารถทำได้.\+ใน GNU grep(แม้ว่าจะไม่ใช่ POSIX หรือสนับสนุนโดยการใช้งานอื่น ๆ ) และคุณสามารถทำได้(.)\1ใน GNU egrep(แม้ว่าจะไม่ใช่ POSIX หรือสนับสนุนโดยการใช้งานอื่น ๆ รวมถึง GNU awk)

การเพิ่ม\xตัวดำเนินการไม่ใช่วิธีเดียวในการเพิ่มตัวดำเนินการเพิ่มเติมในวิธีที่เข้ากันได้แบบย้อนหลัง ยกตัวอย่างเช่นใช้perl (?...)ที่ยังคงเข้ากันได้กับ Eres เป็น(?=...)ไม่ถูกต้องใน Eres .*?เดียวกันสำหรับ vimสำหรับผู้ประกอบการที่คล้ายกันทำแตกต่างกันโดยการแนะนำ\@=หรือ.\{-}ยกตัวอย่างเช่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.