regex ที่ถูกต้องไม่ทำงานใน grep


13

ฉันมี regex นี้:

(?<=prefix).*$

ซึ่งส่งกลับอักขระใด ๆ ต่อไปนี้สตริง "คำนำหน้า" และทำงานได้ดีกับเอ็นจิน regex ออนไลน์ใด ๆ (เช่นhttps://regex101.com ) ปัญหาคือเมื่อฉันใช้ regex นั้นใน bash:

grep '(?<=prefix).*$' <<< prefixSTRING

มันไม่ตรงกับอะไรเลย ทำไม regex ไม่ทำงานกับ grep


11
นี่เป็นการเน้นว่าทำไม regex101 จึงต้องการตัวเลือกรสชาติ POSIX แบบเดียวกับ JS, Perl / PHP และ Python ฉันไม่สามารถนับจำนวนครั้งที่ฉันต้องการได้
Jared Smith


นอกจากนี้การ.*$จับคู่สตริงใด ๆ จนถึงจุดสิ้นสุดของบรรทัด (หรือจุดสิ้นสุดของสตริง) ไม่ใช่อักขระเพียงตัวเดียว
ilkkachu

คำตอบ:


38

ดูเหมือนว่าคุณจะได้กำหนด regex ที่ถูกต้อง แต่ไม่ได้ตั้งค่าสถานะที่เพียงพอในบรรทัดคำสั่งเพื่อgrepให้เข้าใจ เพราะโดยค่าเริ่มต้นgrepรองรับ BRE และด้วยการ-Eตั้งค่าสถานะ ERE สิ่งที่คุณมี (look-aheads) มีให้เฉพาะในรสชาติ PCRE regex ซึ่งรองรับเฉพาะใน GNU grepด้วยการ-Pตั้งค่าสถานะ

สมมติว่าคุณต้องแยกเฉพาะการจับคู่สายหลังจากที่prefixคุณจะต้องเพิ่มธงพิเศษ-oเพื่อแจ้งให้ทราบว่าgrepการพิมพ์ที่เท่านั้นส่วนการจับคู่เป็น

grep -oP '(?<=prefix).*$' <<< prefixSTRING

นอกจากนี้ยังมีรุ่นgrepที่รองรับไลบรารี PCRE ตามค่าเริ่มต้นpcregrepซึ่งคุณสามารถทำได้

pcregrep -o '(?<=prefix).*$' <<< prefixSTRING

คำอธิบายโดยละเอียดเกี่ยวกับรสชาติที่หลากหลายของ regex ได้อธิบายไว้ในคำตอบและเครื่องมือของไจล์ที่นำมาใช้ในการดำเนินการแต่ละข้อ


38

การแสดงออกปกติมาในรสชาติที่แตกต่างมากมาย สิ่งที่คุณแสดงคือนิพจน์ทั่วไปที่เหมือน Perl (PCRE, "Perl Compatible Regular Expression")

grepนิพจน์ปกติ POSIX ใด เหล่านี้คือนิพจน์ทั่วไปพื้นฐาน (BRE) และนิพจน์ทั่วไปเพิ่มเติม (ERE หากgrepใช้กับ -Eตัวเลือก) ดูคู่มือสำหรับre_formatหรือregexหรือคู่มือที่คล้ายกันของคุณgrepอ้างอิงในระบบของคุณหรือข้อความมาตรฐาน POSIX ที่ฉันเพิ่งเชื่อมโยง

หากคุณใช้ GNU grepคุณจะสามารถใช้นิพจน์ทั่วไปที่เหมือน Perl ได้หากคุณใช้grepกับตัวเลือกที่grepเจาะจงของGNU-P

โปรดทราบว่าการgrepส่งคืนบรรทัดเป็นค่าเริ่มต้นไม่ใช่สตริงย่อยจากบรรทัด อีกครั้งด้วย GNU grep(และgrepการใช้งานอื่น ๆ) คุณอาจใช้-oตัวเลือกเพื่อรับบิตที่ตรงกับนิพจน์ที่ระบุจากแต่ละบรรทัด

โปรดทราบว่าทั้งสอง-Pและ-oส่วนขยายที่ไม่ได้มาตรฐานสเปคของ POSIXgrep

หากคุณไม่ได้ใช้ GNU grepคุณอาจใช้sedแทนการรับบิตระหว่างสตริงprefixและจุดสิ้นสุดของบรรทัด:

sed -n 's/.*prefix\(.*\)/\1/p' file

สิ่งนี้ทำเพื่อพิมพ์เฉพาะบรรทัดที่sedจัดการเพื่อใช้การทดแทนที่กำหนดให้ การเปลี่ยนตัวผู้เล่นจะเข้ามาแทนที่สายทั้งที่ตรงกับการแสดงออก (ซึ่งเป็น BRE) prefixกับชิ้นส่วนของมันที่เกิดขึ้นหลังจากสตริง

โปรดทราบว่าหากมีหลายอินสแตนซ์ของprefixหนึ่งบรรทัดการsedแปรผันจะคืนค่าสตริงหลังอันสุดท้ายในขณะที่การgrepเปลี่ยนแปลงของGNU จะคืนค่าสตริงหลังจากอันแรก (ซึ่งจะรวมถึงอินสแตนซ์อื่นของprefix)

การsedแก้ปัญหาจะเป็นแบบพกพาไปยังระบบเหมือน Unix ทั้งหมด


6

ตามที่คำตอบอื่น ๆ ระบุไว้grepอย่าใช้รสชาติ regex กับ lookbehinds (โดยค่าเริ่มต้นกับ GNU grepหรือไม่ใช้กับรุ่นอื่น ๆ เลย)

หากคุณพบว่าคุณไม่สามารถใช้ GNU grepหรือpcregrepคุณสามารถใช้perlหากคุณมี

บรรทัดคำสั่งที่เทียบเท่ากับperlจะเป็น:

perl -ne 'print if /(?<=prefix).*$/' <<< prefixSTRING

คุณใส่ regex ที่ต้องการระหว่างเครื่องหมายทับ ในขณะที่คุณกำลังใช้ Perl นี้ใช้รสชาติ regex ของ Perl


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