วิธีใช้ [\ w] + ในการแสดงออกปกติใน sed?


24

ฉันอยู่บน Windows แต่ฉันเดาว่าคำถามของฉันยังคงอยู่ที่นี่

C:\Users\User>grep --version
GNU grep 2.6.3

C:\Users\User>sed --version
GNU sed version 4.2.1

ฉันสังเกตเห็นว่างานต่อไปนี้ (การแสดงผลhere):

echo here | grep -E "\w+"
echo here | grep -E "[her]+"

แต่สิ่งนี้ไม่ทำงาน (ไม่แสดงผลอะไร):

echo here | grep -E "[\w]+"

สิ่งนี้จะทำอีกครั้ง (การส่งออกhere):

echo here | grep -P "[\w]+"

ดังนั้น[\w]สิ่งที่เฉพาะเจาะจงกับการแสดงออกปกติ Perl ฉันคิดว่า ถูกต้องไหม

งั้นมาพูดsedกัน งานนี้ (การแสดงผลgone):

echo here | sed -r "s/\w+/gone/"
echo here | sed -r "s/[her]+/gone/"

และอีกครั้งสิ่งนี้ไม่ได้ (เอาท์พุทhere):

echo here | sed -r "s/[\w]+/gone/"

ตอนนี้ฉันจะเปิดใช้งานการแสดงออกปกติ Perl สำหรับ sed - มีวิธีใด?

คำตอบ:


11

เครื่องมือและรุ่นที่แตกต่างกันของรุ่นนั้นรองรับนิพจน์ทั่วไปที่แตกต่างกัน เอกสารของแต่ละคนจะบอกคุณว่าพวกเขาสนับสนุนอะไร

มาตรฐานมีอยู่เพื่อให้เราสามารถพึ่งพาชุดคุณลักษณะขั้นต่ำที่มีอยู่ในแอปพลิเคชันที่สอดคล้องทั้งหมด

ตัวอย่างเช่นการใช้งานที่ทันสมัยทั้งหมดของsedและgrepใช้การแสดงออกปกติขั้นพื้นฐานตามที่ระบุโดย POSIX (อย่างน้อยหนึ่งรุ่นหรือมาตรฐานอื่น ๆ แต่มาตรฐานนั้นไม่ได้มีการพัฒนามากในเรื่องนั้นในช่วงไม่กี่ทศวรรษที่ผ่านมา)

ใน POSIX BRE และ ERE คุณมี[:alnum:]คลาสอักขระ ที่ตรงกับตัวอักษรและตัวเลขในสถานที่ของคุณ (โปรดทราบว่ามักจะมีมากเกินกว่าที่a-zA-Z0-9ยกเว้นสถานที่คือ C)

ดังนั้น:

grep -x '[[:alnum:]_]\{1,\}'

ตรงกับหนึ่งหรือมากกว่าหนึ่ง alnums หรือ _

[\w]ถูกต้องตาม POSIX wเพื่อให้ตรงกับทับขวาหรือ ดังนั้นคุณจะไม่พบ a grepหรือsedการนำไปใช้ที่มีอยู่ (ยกเว้นผ่านตัวเลือกที่ไม่ได้มาตรฐาน)

พฤติกรรมของ\wคนเดียวไม่ได้ถูกระบุโดย POSIX ดังนั้นการใช้งานจะได้รับอนุญาตให้ทำสิ่งที่พวกเขาต้องการ GNU grepเสริมว่านานมาแล้ว

GNU grepเคยมีเอ็นจิ้น regexp ของตัวเอง แต่ตอนนี้มันใช้ libc ของ GNU หนึ่งตัว (แม้ว่ามันจะฝังตัวสำเนาของมันเอง)

มันหมายถึงการจับคู่ alnums และขีดล่างในสถานที่ของคุณ อย่างไรก็ตามในปัจจุบันมีข้อผิดพลาดที่ตรงกับอักขระไบต์เดียวเท่านั้น (ตัวอย่างเช่นไม่ใช่éในโลแคล UTF-8 แม้ว่าจะเป็นตัวอักษรที่ชัดเจนและถึงแม้ว่ามันจะจับคู่éในโลแคลทั้งหมดที่éนั้น ตัวอักษร)

นอกจากนี้ยังมี\wผู้ประกอบการ regexp ใน Perl regexp และใน PCRE PCRE / perl ไม่ใช่ POSIX นิพจน์ปกติ แต่เป็นอีกสิ่งหนึ่งโดยสิ้นเชิง

ขณะนี้มีวิธีการที่ GNU grep -Pใช้ PCRE -Pก็มีปัญหาเช่นเดียวกับที่โดยไม่ต้อง สามารถใช้งานได้โดยใช้(*UCP)(แม้ว่าจะมีผลข้างเคียงในโลแคลที่ไม่ใช่ UTF8)

GNU sedยังใช้ regex ของ GNU libc สำหรับ regexps ของตัวเอง จะใช้มันในทางดังกล่าว แต่ที่มันไม่ได้มีข้อผิดพลาดเช่นเดียวกับ grepGNU

GNU sedไม่รองรับ PCREs มีหลักฐานบางอย่างในรหัสที่เคยลองมาแล้ว แต่ดูเหมือนจะไม่อยู่ในระเบียบวาระอีกต่อไป

หากคุณต้องการนิพจน์ปกติของ Perl ให้ใช้perlแม้ว่า

มิฉะนั้นผมจะบอกว่าแทนที่จะพยายามที่จะพึ่งพาคุณลักษณะปลอมที่ไม่ได้มาตรฐานของการดำเนินงานเฉพาะของsed/ มันจะดีกว่าที่จะติดกับมาตรฐานและการใช้งานgrep[_[:alnum:]]


[_[:alnum:]]เป็นวิธีแก้ปัญหาที่ดีซึ่งทำให้ฉันสามารถขยายได้เหมือน[\w/]( [_[:alnum:]/]ในกรณีนี้)
bers

1
คำตอบนี้ล้าสมัยตอนนี้มีเรื่องที่เกี่ยวกับข้อ จำกัด ของ grepGNU
Stéphane Chazelas

7

คุณถูกต้อง - \wเป็นส่วนหนึ่งของ PCRE - การแสดงออกปกติที่เข้ากันได้กับ Perl มันไม่ได้เป็นส่วนหนึ่งของ regex 'มาตรฐาน' http://www.regular-expressions.info/posix.html

บางรุ่นsedอาจรองรับ แต่ฉันขอแนะนำวิธีที่ง่ายที่สุดคือการใช้perlในsedโหมดโดยระบุการ-pตั้งค่าสถานะ (พร้อมกับ-e) (รายละเอียดเพิ่มเติมในperlrun)

แต่คุณไม่จำเป็นต้องใช้[]มันในตัวอย่างนั้น - สำหรับกลุ่มของสิ่งที่ถูกต้อง

echo here  | perl -pe 's/\w+/gone/'

หรือบน Windows:

C:\>echo here  | perl -pe "s/\w+/gone/"
gone
C:\>echo here  | perl -pe "s/[\w\/]+/gone/"
gone

ดูperlreข้อมูลเพิ่มเติมเกี่ยวกับ PCRE

คุณสามารถรับ Perl ได้ที่นี่: http://www.activestate.com/activeperl/downloads


โปรดทราบความแตกต่างระหว่าง\wและ[\w]ในคำถามของฉัน ฉันจะอัปเดตด้วยเอาต์พุตของแต่ละคำสั่งเพื่อให้ชัดเจนว่าอันไหนใช้ได้และอันไหนไม่ได้ โดยเฉพาะอย่างยิ่งsedเข้าใจแต่ไม่\w [\w]นอกจากนี้ฉันต้อง[\w]ทำงานเพราะฉันต้องการใช้[\w/]เป็นตัวอย่าง
bers

ในกรณีนี้อาจเป็นปัญหาการอ้างอิง ไม่ว่าจะด้วยวิธีใด - perlทำได้ :)
Sobrique

ขอบคุณ! คำตอบของStéphane Chazelas นั้นใกล้กับสิ่งที่ฉันถาม (เพราะฉันไม่ได้ติดตั้ง Perl - ผู้ใช้ Windows du * b ฉันเดา) ดังนั้นฉันจึงยอมรับคำตอบของเขา
bers

ไม่เป็นไร - แต่ฉันขอแนะนำให้ติดตั้ง Perl บน Windows มันเป็นหนึ่งในสิ่งแรกที่เกิดขึ้นกับฉันและฉันคิดว่ามันมีประโยชน์มาก
Sobrique

\wอยู่ใน GNU grep (ใน 80) ก่อนที่จะอยู่ใน perl และใน GNU emacs อาจจะก่อนหน้านั้น
Stéphane Chazelas

1

ฉันสงสัยว่าgrepและsedกำลังตัดสินใจที่แตกต่างกันเมื่อนำไปใช้และเมื่อขยาย[] \wใน perl regex \wหมายถึงอักขระคำใด ๆ และ[]กำหนดกลุ่มเพื่อใช้อักขระใด ๆ ภายในเป็นการแข่งขัน หากคุณ "ขยาย" \wก่อนหน้า[]นั้นจะเป็นคลาสอักขระของอักขระคำทั้งหมด ถ้าคุณทำแทน[]แรกที่คุณจะได้เรียนตัวอักษรสองตัวอักษร\และwดังนั้นมันจะตรงกับรูปแบบใด ๆ ที่มีหนึ่งหรือมากกว่าหนึ่งของบรรดาตัวละครทั้งสอง

ดังนั้นดูเหมือนว่าsedจะเห็น[]และปฏิบัติตามที่มีตัวอักษรที่แน่นอนให้ตรงกับแทนที่จะเคารพลำดับพิเศษ\wเป็นperlและgrepทำ แน่นอนว่า[]มันไม่จำเป็นอย่างสมบูรณ์ในตัวอย่างนี้ แต่อาจมีกรณีที่มันจะมีความสำคัญ แต่คุณสามารถทำให้มันทำงานกับ parens และ ors ได้


ฉันจะแปลกใจถ้าเป็นเช่นนั้น \ เป็นรหัสยกเว้นและคุณจะใช้เพื่อหลีกเลี่ยงตัวคั่น โดยเนื้อแท้นั่นหมายความว่ามันจะต้องมีลำดับความสำคัญสูงกว่าสิ่งอื่นใด ผมคิดว่ามันมีแนวโน้มว่าจะไม่ได้ดำเนินการเพราะ\wไม่ได้เป็นส่วนหนึ่งของข้อมูลจำเพาะแสดงออกปกติ
Sobrique

ดูเหมือนว่าสังเกตุจะเป็นกรณีที่ใช้ gnu sed สำหรับฉัน: echo whe\\ere | sed -r 's/[\w]+/gone/gให้ฉันgonehegoneereราวกับว่ามันจับคู่แต่ละ` and w` และทำการเปลี่ยนตัว
Eric Renouf

ฉันสามารถยืนยันสิ่งที่ Eric Renouf เห็น ดังนั้นเราต้องการที่จะ unescape แบ็กสแลชอย่างใด? :)
bers

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