วิธีการแทนที่ตัวละครซ้ำด้วย sed?


13

เป็นไปได้หรือไม่ที่จะแทนที่การเกิดขึ้นของลำดับอักขระซ้ำโดยไม่วนซ้ำในลำดับเดียวกันอีกครั้ง?

ด้วยการทำsedตามในสถานการณ์ต่อไปนี้ฉันจะได้รับผลลัพธ์ที่กล่าวถึง

$ echo XX | sed -e 's/XX/XoX/g'
XoX  
$ echo XXX | sed -e 's/XX/XoX/g'
XoXX  
$ echo XXXX | sed -e 's/XX/XoX/g'
XoXXoX  

อย่างไรก็ตามฉันคาดว่าผลลัพธ์จะเป็นไปตามลักษณะการทำงานต่อไปนี้

การป้อนข้อมูล:

XX
XXX
XXXX

ผลลัพธ์ที่คาดหวัง:

XoX
XoXoX
XoXoXoX

เป็นไปได้ไหมที่จะบรรลุถึงพฤติกรรมที่คาดหวัง

คำตอบ:


24

คุณทำได้:

> echo XXXX | sed -e ':loop' -e 's/XX/XoX/g' -e 't loop'
XoXoXoX

ด้วย:

  • -e ':loop' : สร้างป้ายกำกับ "วน"
  • -e 't loop' : ข้ามไปที่ป้ายกำกับ "วนรอบ" หากการทดแทนก่อนหน้านี้สำเร็จ

10

ในกรณีนี้การดูล่วงหน้าหรือการมองย้อนกลับจะเป็นประโยชน์ ฉันคิดว่า GNU sedไม่สนับสนุนสิ่งเหล่านี้ ด้วยperl:

perl -ne 's/X(?=X)/Xo/g; print;'

คุณสามารถใช้lookbehind และ lookaheadเช่น:

s/(?<=X)(?=X)/o/g

ที่ไหน:

(?<=X)เป็น lookbehind เชิงบวกการยืนยันความยาวเป็นศูนย์ที่ทำให้แน่ใจว่าเรามี X ก่อนที่ตำแหน่งปัจจุบัน
(?=X)จะเป็น lookahead ที่เป็นบวกการยืนยันที่มีความยาวเป็นศูนย์ที่ทำให้แน่ใจว่าเรามี X หลังจากตำแหน่งปัจจุบัน

ใช้ใน perl หนึ่งซับ:

perl -pe 's/(?<=X)(?=X)/o/g' inputfile

ที่ไหน:

-p ทำให้ Perl ถือว่าวนรอบโปรแกรมที่มีการพิมพ์โดยนัยของบรรทัดปัจจุบัน


5

คำตอบวนซ้ำเป็นวิธีทั่วไปในการทำสิ่งที่คุณถาม

อย่างไรก็ตามในกรณีของข้อมูลสมมติว่าคุณใช้ GNU คุณสามารถทำได้ดังนี้

sed 's/\B/o/g'

\bและ\Bตัวเลือกส่วนขยาย regex :

  • \b จับคู่ขอบเขตของคำเช่นการเปลี่ยนจากอักขระ "คำ" เป็น "ไม่ใช่คำ" หรือในทางกลับกัน
  • \B\bตรงตรงข้ามของ เช่นช่องว่างคำ "ภายใน" สิ่งนี้ทำให้เราสามารถแทรกตัวอักษรภายในคำ แต่ไม่ได้อยู่ข้างนอกตามที่ต้องการ

ลองมันออนไลน์

นี่ถือว่าสมมติว่าอักขระที่ป้อนเข้าเป็นตัวอักษร "คำ" ทั้งหมด


อีกทางเลือกหนึ่งถ้าคุณไม่มี GNU sed หรือถ้าอักขระอินพุตไม่ใช่อักขระ "word" ทั้งหมดคุณยังสามารถบรรลุเป้าหมายได้โดยไม่ต้องวนซ้ำ:

sed 's/./&o/g;s/o$//'

นี่เป็นเพียงการวางoหลังจากตัวละครทุกตัวและจากนั้นลบสุดท้ายoจากสตริง

ลองมันออนไลน์


1
สมมติว่าสตริงอินพุตประกอบด้วยจำนวนXและไม่มีอะไรอื่น การแก้ปัญหาทั้งสองล้มเหลวถ้ามีตัวละครอื่น ๆ ในปัจจุบัน ...
AnoE

@AnoE ในตัวอย่างที่สองที่ได้รับการแก้ไขด้วยการเปลี่ยนXโดย.ง่าย โปรดดูการแก้ไข
บาดเจ็บทางดิจิทัล

ไม่เท่ากับกรณีที่ OP ให้ เขาให้ REs ที่แน่นอนที่เขาต้องการ (เปลี่ยนการเกิดขึ้นของ XX ในสตริง) เวอร์ชันของคุณให้ผลลัพธ์เดียวกับของเขาสำหรับสตริงอินพุตเดียวกันที่เขาให้ ไม่ใช่สำหรับสตริงอินพุตทั่วไป
AnoE

4

ฉันตรวจสอบว่ามีธงประเภทใดที่จะทำให้สิ่งนี้เกิดขึ้น
แม้ว่าพฤติกรรมนั้นจะอยู่ที่นั่น แต่ก็จะต้องใช้ทรัพยากรสูง

อย่างไรก็ตามในกรณีการใช้งานเฉพาะนี้เป็นไปได้ที่จะมีการแสดงออกเพียงสองครั้งและบรรลุฟังก์ชั่นที่จำเป็น นั่นคือด้วยsedการแสดงออกซ้ำ 2

echo XX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'     # outputs XoX
echo XXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'    # outputs XoXoX
echo XXXX | sed -e 's/XX/XoX/g' -e 's/XX/XoX/g'   # outputs XoXoXoX
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.