วิธีการแยกข้อความจากสตริงโดยใช้ sed?


98

สตริงตัวอย่างของฉันมีดังนี้:

This is 02G05 a test string 20-Jul-2012

02G05ตอนนี้จากสตริงดังกล่าวข้างต้นที่ฉันต้องการที่จะดึง สำหรับสิ่งนั้นฉันลอง regex ต่อไปนี้ด้วย sed

$ echo "This is 02G05 a test string 20-Jul-2012" | sed -n '/\d+G\d+/p'

แต่คำสั่งด้านบนไม่พิมพ์อะไรเลยและเหตุผลที่ฉันเชื่อคือมันไม่สามารถจับคู่อะไรกับรูปแบบที่ฉันให้มาได้

คำถามของฉันคือฉันทำอะไรผิดที่นี่และจะแก้ไขอย่างไร

เมื่อฉันลองใช้สตริงและรูปแบบด้านบนด้วย python ฉันได้ผลลัพธ์

>>> re.findall(r'\d+G\d+',st)
['02G05']
>>>

6
sedงูหลามไม่แน่นอน รสชาติ regex ของพวกเขาแตกต่างกันมาก
tripleee

คำตอบ:


96

รูปแบบอาจจะไม่ได้รับการสนับสนุนจากคุณ\d sedลอง[0-9]หรือ[[:digit:]]แทน

หากต้องการพิมพ์เฉพาะการจับคู่จริง (ไม่ใช่ทั้งบรรทัดที่ตรงกัน) ให้ใช้การเปลี่ยนตัว

sed -n 's/.*\([0-9][0-9]*G[0-9][0-9]*\).*/\1/p'

6
ขอบคุณที่ทำงานได้ดี แต่ฉันมีคำถามว่าเหตุใดจึง.*จำเป็นกับ regex ของคุณเพราะเมื่อฉันลองsed -n 's/\([0-9]\+G[0-9]\+\)/\1/p'ใช้เพียงแค่พิมพ์ทั้งบรรทัด
RanRag

7
นั่นเป็นเหตุผลว่าทำไม? แทนที่สิ่งที่มาก่อนและหลังการจับคู่ด้วย norhing จากนั้นพิมพ์ทั้งบรรทัด
tripleee

1
@tripleee นี้พิมพ์2G05ไม่ได้02G05เท่านั้น นิพจน์ที่ใช้งานได้คือ's/.*\([0-9][0-9]G[0-9][0-9]*\).*/\1/p'
Kshitiz Sharma

1
ฮาร์ดโค้ดให้เป็นตัวเลขสองหลัก สิ่งที่ต้องการsed -n 's/\(.*[^0-9]\)\?\([0-9][0-9]*G[0-9][0-9]*\).*/\2/p'จะเป็นเรื่องทั่วไปมากขึ้น (ฉันถือว่าการsedสนับสนุนของคุณ\?เป็นศูนย์หรือหนึ่งครั้ง)
tripleee

ดูเพิ่มเติมstackoverflow.com/a/48898886/874188สำหรับวิธีการแทนที่ทั่วไปอื่น ๆ Perl หนีเหมือน\w, \sฯลฯ
tripleee

102

ใช้แล้วเป็นgrep -Eไง?

echo "This is 02G05 a test string 20-Jul-2012" | grep -Eo '[0-9]+G[0-9]+'

3
+1 สิ่งนี้ง่ายกว่าและจะจัดการกรณีที่มีการแข่งขันหลายรายการในบรรทัดเดียวกันได้อย่างถูกต้อง sedอาจมีการคิดค้นสคริปต์ที่ซับซ้อนสำหรับกรณีนั้น แต่ทำไมต้องกังวล?
tripleee

egrepใช้ regexp แบบขยายsedและgrepใช้ regexp มาตรฐาน egrepหรือgrep -eหรือsed -Eใช้ regexp แบบขยายและโค้ด python ในคำถามใช้ PCRE, (perl common regular expression) GNU grep สามารถใช้ PCRE พร้อม-Pตัวเลือก
Felipe Buccioni

@FelipeBuccioni ที่จริงควรจะเป็นegrepหรือgrep -Eหรือsed -r
SensorSmith

สำหรับการแข่งขันเดี่ยว (ครั้งแรก) ให้ต่อท้าย "| หัว -1` (ไม่มีแบ็คทิก) ตามคำตอบนี้สำหรับคำถามอื่น
SensorSmith

1
grepมี-m 1ที่จะหยุดหลังจากที่นัดแรก
tripleee

5

sedไม่รู้จัก\dใช้[[:digit:]]แทน คุณจะต้องหนี+หรือใช้-rสวิตช์ ( -Eบน OS X)

โปรดทราบว่าใช้[0-9]งานได้เช่นกันสำหรับตัวเลขอาหรับ - ฮินดู


ฉันพยายามsed -n '/[0-9]\+G[0-9]\+/p'แล้ว ตอนนี้มันพิมพ์สตริงทั้งหมด
RanRag

@Noob: คุณจะต้องใช้เพื่อทดแทนไม่รวมส่วนที่คุณไม่ต้องการที่จะพิมพ์
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

5

ลองสิ่งนี้แทน:

echo "This is 02G05 a test string 20-Jul-2012" | sed 's/.* \([0-9]\+G[0-9]\+\) .*/\1/'

แต่โปรดทราบว่าหากมีสองรูปแบบในหนึ่งบรรทัดระบบจะพิมพ์ลายที่ 2


หรือโดยทั่วไปแล้วรายการสุดท้ายหากมีการแข่งขันหลายรายการ
tripleee

0

ลองใช้rextract มันจะช่วยให้คุณแยกข้อความโดยใช้นิพจน์ทั่วไปและจัดรูปแบบใหม่

ตัวอย่าง:

$ echo "This is 02G05 a test string 20-Jul-2012" | ./rextract '([\d]+G[\d]+)' '${1}'

2G05

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