เมื่อ regexp มีกลุ่มอาจมีมากกว่าหนึ่งวิธีในการจับคู่สตริงกับมัน: regexps กับกลุ่มไม่ชัดเจน ยกตัวอย่างเช่นพิจารณา regexp และสตริง^.*\([0-9][0-9]*\)$ a12มีความเป็นไปได้สองอย่าง:
- ตรง
aกับ.*และ2ต่อต้าน[0-9]*; จะถูกจับคู่โดย1[0-9]
- จับคู่
a1กับ.*และสตริงที่ว่างเปล่ากับ[0-9]*; จะถูกจับคู่โดย2[0-9]
Sed เช่นเดียวกับเครื่องมือ regexp อื่น ๆ ทั้งหมดออกมีใช้กฎการจับคู่ที่ยาวที่สุดที่เร็วที่สุด: มันพยายามจับคู่ส่วนที่มีความยาวตัวแปรแรกกับสตริงที่ยาวที่สุดเท่าที่จะทำได้ หากพบวิธีจับคู่ส่วนที่เหลือของสตริงกับส่วนที่เหลือของ regexp ให้ปรับ มิฉะนั้น sed จะพยายามจับคู่ที่ยาวที่สุดถัดไปสำหรับส่วนที่มีความยาวผันแปรแรกและลองอีกครั้ง
นี่คือการแข่งขันกับสตริงที่ยาวที่สุดเป็นครั้งแรกa1กับดังนั้นกลุ่มเดียวที่ตรงกับ.* 2หากคุณต้องการให้กลุ่มเริ่มต้นก่อนหน้านี้เครื่องยนต์ regexp บางตัวช่วยให้คุณ.*โลภน้อยลง แต่ยังไม่มีคุณสมบัติดังกล่าว ดังนั้นคุณต้องลบความกำกวมด้วยสมอเพิ่มเติมบางอย่าง ระบุว่าผู้นำ.*ไม่สามารถลงท้ายด้วยตัวเลขดังนั้นตัวเลขแรกของกลุ่มคือการจับคู่ที่เป็นไปได้ครั้งแรก
หากกลุ่มของตัวเลขไม่สามารถอยู่ที่จุดเริ่มต้นของบรรทัด:
sed -n 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p'
หากกลุ่มของตัวเลขสามารถอยู่ที่จุดเริ่มต้นของบรรทัดและ sed ของคุณสนับสนุน\?ผู้ประกอบการสำหรับชิ้นส่วนเพิ่มเติม:
sed -n 's/^\(.*[^0-9]\)\?\([0-9][0-9]*\).*/\1/p'
หากกลุ่มของตัวเลขสามารถอยู่ที่จุดเริ่มต้นของบรรทัดการผสานกับโครงสร้าง regexp มาตรฐาน:
sed -n -e 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p' -e t -e 's/^\([0-9][0-9]*\).*/\1/p'
โดยวิธีการที่มันเป็นเรื่องที่กฎแข่งขันที่เก่าแก่ที่สุดที่ยาวที่สุดที่ทำให้ตรงกับหลักหลังคนแรกมากกว่าต่อมา[0-9]*.*
.*โปรดทราบว่าถ้ามีหลายลำดับของตัวเลขในบรรทัดโปรแกรมของคุณมักจะแยกลำดับสุดท้ายของตัวเลขอีกครั้งเพราะกฎการแข่งขันที่ยาวที่สุดเร็วที่สุดเท่าที่นำไปใช้กับการเริ่มต้น หากคุณต้องการแยกลำดับของตัวเลขแรกคุณต้องระบุว่าสิ่งที่มาก่อนคือลำดับของตัวเลขที่ไม่ใช่
sed -n 's/^[^0-9]*\([0-9][0-9]*\).*$/\1/p'
โดยทั่วไปหากต้องการแยกคู่แรกของ regexp คุณจำเป็นต้องคำนวณการปฏิเสธของ regexp นั้น ในขณะที่สิ่งนี้เป็นไปได้ในทางทฤษฎีขนาดของการปฏิเสธจะเพิ่มขึ้นแบบทวีคูณเมื่อเทียบกับขนาดของ regexp ที่คุณกำลังปฏิเสธดังนั้นนี่จึงเป็นสิ่งที่ไม่จริง
ลองพิจารณาตัวอย่างอื่นของคุณ:
sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p'
ตัวอย่างนี้จริงแสดงปัญหาเดียวกัน แต่คุณไม่เห็นในอินพุตปกติ ถ้าคุณกินมันhello CONFIG_FOO_CONFIG_BARแล้วคำสั่งดังกล่าวพิมพ์ออกมาไม่ได้CONFIG_BARCONFIG_FOO_CONFIG_BAR
มีวิธีพิมพ์การจับคู่ครั้งแรกด้วย sed แต่มันค่อนข้างยุ่งยากเล็กน้อย:
sed -n -e 's/\(CONFIG_[a-zA-Z0-9_]*\).*/\n\1/' -e T -e 's/^.*\n//' -e p
(สมมติว่า sed ของคุณรองรับ\nเพื่อหมายถึงบรรทัดใหม่ในsข้อความแทนที่) การทำงานนี้เนื่องจาก sed ค้นหาการจับคู่ที่เร็วที่สุดของ regexp และเราจะไม่พยายามจับคู่สิ่งที่นำหน้าCONFIG_…บิต เนื่องจากไม่มีการขึ้นบรรทัดใหม่ภายในบรรทัดเราจึงสามารถใช้เป็นเครื่องหมายชั่วคราวได้ Tคำสั่งว่าจะให้ขึ้นถ้าก่อนหน้านี้sคำสั่งไม่ตรงกับ
เมื่อคุณไม่สามารถหาวิธีที่จะทำบางสิ่งบางอย่างใน sed ให้หันไป awk คำสั่งต่อไปนี้พิมพ์การจับคู่ที่ยาวที่สุดเร็วที่สุดของ regexp:
awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}'
และถ้าคุณรู้สึกอยากทำให้มันง่ายขึ้นให้ใช้ Perl
perl -l -ne '/[0-9]+/ && print $&' # first match
perl -l -ne '/^.*([0-9]+)/ && print $1' # last match