sed chuyển đổi 4 không gian thành 2


14

Làm thế nào để chuyển đổi 4 không gian thành 2 không gian với sed? Có thể không?

Tôi tìm thấy cái này nhưng nó chuyển đổi tab thành khoảng trắng:

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

Câu trả lời:


13

Tập lệnh bạn đã đăng chuyển đổi các khoảng trắng 4 * n thành n tab, chỉ khi các khoảng trắng đó được đi trước bởi các tab.

Nếu bạn muốn thay thế 4 khoảng trắng bằng 2 khoảng trắng, nhưng chỉ trong thụt lề, trong khi có thể thực hiện bằng sed, tôi khuyên bạn nên thay thế Perl.

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

Trong sed:

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

Bạn có thể muốn sử dụng indentthay thế.


Tôi đã nhậnNested quantifiers in regex; marked by <-- HERE in m/^( {4}* <-- HERE )/ at -e line 1.
eddygeek

1
@eddygeek Ồ, thực sự, đó và một vài lỗi khác. Tôi đã thay thế gobbledygook bằng mã perl thực tế.
Gilles 'SO- ngừng trở thành ác quỷ'

5

Không phải cách làm việc đơn giản:

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

Nếu không, đăng một số đầu vào nơi nó thất bại.


1
Điều này không bị hạn chế đến đầu dòng. Nếu bạn neo nó ở đó, nó sẽ không hoạt động cho nhiều trận đấu. Vì vậy, chúng tôi đang ở unix.stackexchange.com/a/375200/259620 bên dưới.
geek-merlin

Điều này không hoạt động nếu bạn có sự kết hợp của 2 không gian và 4 không gian, bởi vì hai vết lõm của hai sẽ được tính là bốn ...
Matt Fletcher

@aexl: Đó không phải là yêu cầu của OP
Thor

@mattfletcher: câu hỏi là về việc thay thế 4 khoảng trắng bằng 2, vì vậy tôi không thấy quan điểm của bạn
Thor

4

Nếu chỉ các không gian hàng đầu sẽ được chuyển đổi:

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

Với nhận xét:

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'

Cũng nhìn vào 'ts'thiết lập và :retablệnh của vim


Sử dụng giải pháp vim của bạn, có cách nào để chỉnh sửa hàng loạt tệp như vậy với vim không? Nếu không, tôi đoán tôi sẽ phải tạo một macro?
chrisjlee

Lưu ý rằng 'ts':retabkhông phải là giải pháp cho câu hỏi, nhưng có liên quan và có thể giúp giải quyết mục tiêu chung của bạn. Bạn có thể làm vim -- *.c,:set ts=... và sau đó :argdo retabhoặc :argdo retab!. Xem thêm 'sw'tùy chọn và khả năng thụt lề của vim.
Stéphane Chazelas

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

Nó hoạt động bằng cách chia các không gian hàng đầu thành bốn trường hợp của cùng một nhóm (vì vậy tất cả chúng đều bằng nhau) và sau đó thay thế chúng chỉ bằng hai phiên bản của nhóm.


Làm thế nào để cải thiện các giải pháp hiện có?
Philippos

1
Nó bảo tồn các khoảng trắng, chỉ ảnh hưởng đến khoảng trắng hàng đầu, không yêu cầu cờ toàn cầu, có thể dễ dàng điều chỉnh để xử lý bất kỳ số lượng khoảng trống (hoặc tab) nào trên cả hai mặt của thay thế và không sử dụng các lệnh sed phức tạp hơn mà có thể được đặt ra cho người dùng bình thường hơn. Như với nhiều thứ, cho dù đó là một cải tiến khá chủ quan, nhưng nói cho bản thân tôi: tìm thấy điều này trong một kịch bản sẽ dễ dàng nhanh chóng hơn đáng kể so với một số giải pháp khác được liệt kê.
Mal

Hấp dẫn. Vui mừng tôi đã hỏi. Thông thường phản ứng được coi là xấu xa hơn là cờ toàn cầu. Nhưng bạn có thể dễ dàng đạt được điều tương tự với tập lệnh di động hơn (tránh \+). Cảm ơn bạn.
Philippos

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

Điều đó chỉ nên siết chặt các chuỗi hàng đầu của không gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.