Làm cách nào tôi có thể xóa tất cả văn bản giữa các dấu ngoặc nhọn lồng nhau trong tệp văn bản nhiều dòng?


9

Câu hỏi này xuất phát từ Làm thế nào tôi có thể xóa tất cả văn bản giữa các dấu ngoặc nhọn trong tệp văn bản nhiều dòng? (chỉ giống nhau, nhưng không có yêu cầu cho lồng).

Thí dụ:

This is {
{the multiline
text} file }
that wants
{ to {be
changed}
} anyway.

Nên trở thành:

This is 
that wants
 anyway.

Có thể làm điều này với một số loại lệnh bash một dòng (awk, sed, perl, grep, cut, tr ... vv) không?

Câu trả lời:


13
$ sed ':again;$!N;$!b again; :b; s/{[^{}]*}//g; t b' file3
This is 
that wants
 anyway.

Giải trình:

  • :again;$!N;$!b again

    Điều này đọc trong toàn bộ tập tin.

    :againlà một nhãn hiệu Nđọc ở dòng tiếp theo và $!Nđọc ở dòng tiếp theo với điều kiện chúng ta chưa ở dòng cuối cùng. $!b againcác chi nhánh trở lại againnhãn với điều kiện đây không phải là dòng cuối cùng.

  • :b

    Điều này xác định một nhãn b.

  • s/{[^{}]*}//g

    Điều này loại bỏ văn bản trong dấu ngoặc nhọn miễn là văn bản không chứa dấu ngoặc trong.

  • t b

    Nếu lệnh thay thế ở trên dẫn đến thay đổi, hãy quay lại nhãn b. Theo cách này, lệnh thay thế được lặp lại cho đến khi tất cả các nhóm nẹp được loại bỏ.


3

Một cách tiếp cận Perl:

$ perl -F"" -a00ne 'for (@F){$i++ if /{/; $i||print; $i-- if /}/}' file
This is 
that wants
 anyway

Giải trình

  • -a: bật tự động phân tách trên dấu phân cách tệp được cung cấp bởi -Fvào @Fmảng.
  • -F"": đặt dấu tách trường đầu vào thành trống, điều này sẽ dẫn đến mỗi phần tử @Flà một trong các ký tự đầu vào.
  • -00: bật "chế độ đoạn", trong đó "dòng" được định nghĩa là hai ký tự dòng mới liên tiếp. Điều này có nghĩa là toàn bộ tệp trong trường hợp này sẽ được coi là một dòng duy nhất. Nếu tệp của bạn có thể có nhiều đoạn và dấu ngoặc có thể kéo dài nhiều đoạn, -0777thay vào đó hãy sử dụng .
  • -ne: đọc tệp đầu vào và áp dụng tập lệnh được cung cấp -echo từng dòng.

Bản thân kịch bản thực sự khá đơn giản. Một bộ đếm được tăng lên mỗi lần một cái {được nhìn thấy và giảm xuống cho mỗi bộ đếm }. Điều này có nghĩa là khi bộ đếm bằng 0, chúng ta không ở trong ngoặc và nên in:

  • for (@F){}: làm điều này cho từng yếu tố của @F, từng ký tự trong dòng.
  • $i++ if /{/;: tăng thêm $imột nếu nhân vật này là một{
  • $i||print;: in trừ khi $iđược đặt (0 được tính là không đặt).
  • $i-- if /}/: giảm $ibởi một nếu nhân vật này là một}
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.