sed แปลง 4 ช่องว่างเป็น 2


14

วิธีหนึ่งจะแปลง 4 ช่องว่างเป็น 2 ช่องว่างด้วยsed? เป็นไปได้ไหม?

ฉันพบสิ่งนี้ แต่มันแปลงแท็บเป็นช่องว่าง:

sed -r ':f; s|^(\t*)\s{4}|\1\t|g; t f' file

คำตอบ:


13

สคริปต์ที่คุณโพสต์จะแปลงช่องว่าง 4 * n เป็นแท็บเฉพาะเมื่อช่องว่างนั้นนำหน้าด้วยแท็บเท่านั้น

หากคุณต้องการแทนที่ 4 ช่องว่างด้วย 2 ช่องว่าง แต่เป็นการเว้นย่อหน้าเท่านั้นในขณะที่เป็นไปได้ที่จะทำด้วย sed ฉันแนะนำ Perl แทน

perl -pe 's{^((?: {4})*)}{" " x (2*length($1)/4)}e' file

ใน sed:

sed -e 's/^/~/' -e ': r' -e 's/^\( *\)~    /\1  ~/' -e 't r' -e 's/~//' file

คุณอาจต้องการใช้indentแทน


ฉันได้รับNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek

1
@eddygeek โอ้แน่นอนว่าและข้อบกพร่องอื่น ๆ ฉันแทนที่ gobbledygook ด้วยรหัส Perl จริง
Gilles 'หยุดความชั่วร้าย'

5

วิธีการตรงไปตรงมาใช้ไม่ได้:

sed -r 's/ {4}/  /g'

ถ้าไม่โพสต์อินพุตที่มันล้มเหลว


1
สิ่งนี้ไม่ได้ถูก จำกัด ไว้ที่จุดเริ่มต้นของบรรทัด หากคุณยึดไว้ตรงนั้นมันจะไม่สามารถใช้ได้กับการแข่งขันหลายนัด ดังนั้นเราอยู่ที่unix.stackexchange.com/a/375200/259620ด้านล่าง
geek-merlin

ไม่ทำงานหากคุณมีการรวมกันของ 2 ช่องว่างและ 4 ช่องว่างเพราะสองเยื้องของทั้งสองจะถูกนับเป็นสี่ ...
Matt Fletcher

@ aexl: นั่นไม่ได้เป็นข้อกำหนดโดย OP
Thor

@mattfletcher: คำถามเกี่ยวกับการเปลี่ยนเป็น 4 ช่องว่างมี 2 ดังนั้นผมจึงมองไม่เห็นจุดของคุณ
ธ อร์

4

หากมีการแปลงเฉพาะพื้นที่นำหน้า:

sed 'h;s/[^ ].*//;s/    /  /g;G;s/\n *//'

ด้วยความคิดเห็น:

sed '
  h; # save a copy of the pattern space (filled with the current line)
     # onto the hold space
  s/[^ ].*//; # remove everything starting with the first non-space
              # from the pattern space. That leaves the leading space
              # characters
  s/    /  /g; # substitute every sequence of 4 spaces with 2.
  G; # append a newline and the hold space (the saved original line) to
     # the pattern space.
  s/\n *//; # remove that newline and the indentation of the original
            # line that follows it'

ดูการ'ts'ตั้งค่าและ:retabคำสั่งของกลุ่ม


การใช้โซลูชัน vim ของคุณมีวิธีการแบตช์แก้ไขหลายไฟล์เช่นนั้นด้วย vim หรือไม่? มิฉะนั้นฉันคาดเดาว่าฉันจะต้องสร้างแมโครหรือไม่
chrisjlee

โปรดทราบว่า'ts'และ:retabไม่ใช่คำตอบสำหรับคำถาม แต่เกี่ยวข้องและอาจช่วยแก้ไขเป้าหมายโดยรวมของคุณ คุณสามารถทำอะไรvim -- *.c, :set ts=...แล้วหรือ:argdo retab :argdo retab!ดูเพิ่มเติม'sw'ตัวเลือกและความสามารถในการเยื้องของตัวเองเป็นกลุ่ม
Stéphane Chazelas

2
sed 's/^\( \+\)\1\1\1/\1\1/' file

มันทำงานได้โดยการแบ่งช่องว่างนำออกเป็นสี่อินสแตนซ์ของกลุ่มเดียวกัน (ดังนั้นพวกมันจึงเท่ากันทั้งหมด) จากนั้นแทนที่ด้วยช่องว่างอินสแตนซ์สองกลุ่ม


สิ่งนี้จะปรับปรุงโซลูชันที่มีอยู่ได้อย่างไร
Philippos

1
มันรักษาช่องว่างคี่เพียงส่งผลกระทบต่อช่องว่างชั้นนำไม่จำเป็นต้องมีธงทั่วโลกสามารถ tweaked ได้อย่างง่ายดายเพื่อจัดการจำนวนช่องว่าง (หรือแท็บ) ทั้งสองด้านของการเปลี่ยนและไม่ใช้คำสั่ง sed ที่ซับซ้อนมากขึ้น สามารถวางสำหรับผู้ใช้ที่ไม่เป็นทางการมากขึ้น เช่นเดียวกับหลาย ๆ สิ่งไม่ว่าจะเป็นการปรับปรุงที่ค่อนข้างเป็นอัตวิสัย แต่การพูดเพื่อตัวเอง: การค้นหาสิ่งนี้ในสคริปต์จะง่ายกว่าการค้นหาอย่างรวดเร็วมากกว่าโซลูชันอื่น ๆ ที่ระบุไว้
Mal

น่าสนใจ ดีใจที่ฉันถาม โดยปกติแล้วการอ้างถึงนั้นถือว่าเป็นความชั่วร้ายมากกว่าการปักธงทั่วโลก แต่คุณสามารถบรรลุสิ่งเดียวกันได้อย่างง่ายดายด้วยสคริปต์แบบพกพา (หลีกเลี่ยง\+) ขอขอบคุณ.
Philippos

1
sed 's/    \{2,4\}\( \{0,1\}[^ ].*\)*/  \1/g' <input

นั่นควรบีบลำดับชั้นนำของช่องว่างเท่านั้น

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