Làm thế nào để đệ quy thay thế nhân vật bằng sed?


13

Có thể thay thế các lần xuất hiện của một chuỗi ký tự theo cách đệ quy mà không lặp lại trên cùng một chuỗi không?

Bằng cách thực hiện sednhư trong các kịch bản sau đây, tôi có thể nhận được đầu ra được đề cập.

$ 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  

Tuy nhiên, tôi hy vọng đầu ra sẽ theo hành vi sau.

Đầu vào:

XX
XXX
XXXX

Sản lượng dự kiến:

XoX
XoXoX
XoXoXoX

Có thể đạt được hành vi mong đợi với sed một mình?

Câu trả lời:


24

Bạn có thể làm:

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

Với:

  • -e ':loop' : Tạo nhãn "vòng lặp"
  • -e 't loop' : Chuyển đến nhãn "loop" nếu thay thế trước đó thành công

10

Trong trường hợp cụ thể này, nhìn về phía trước hoặc nhìn phía sau sẽ hữu ích. Tôi nghĩ GNU sedkhông hỗ trợ những thứ này. Với perl:

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

Bạn cũng có thể sử dụng lookbehind và lookahead như:

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

Ở đâu:

(?<=X)là một cái nhìn tích cực, một xác nhận có độ dài bằng 0 đảm bảo rằng chúng ta có X trước vị trí hiện tại
(?=X)là một diện mạo tích cực, một xác nhận có độ dài bằng 0 đảm bảo rằng chúng ta có X sau vị trí hiện tại

Sử dụng trong một lớp lót perl:

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

Ở đâu:

-p khiến Perl giả định một vòng lặp xung quanh chương trình với một bản in ngầm của dòng hiện tại


5

Câu trả lời lặp là cách chung để làm những gì bạn đang yêu cầu.

Tuy nhiên, trong trường hợp dữ liệu của bạn, giả sử bạn đang sử dụng GNU, bạn chỉ cần làm:

sed 's/\B/o/g'

Các tùy chọn \b\Blà các phần mở rộng regex :

  • \b khớp với ranh giới từ, nghĩa là chuyển từ ký tự "từ" sang ký tự "không từ" hoặc ngược lại
  • \Bphù hợp với đối diện của \b. tức là những khoảng trống "bên trong" từ. Điều này cho phép chúng ta chèn các ký tự bên trong một từ nhưng không phải bên ngoài, theo yêu cầu.

Hãy thử trực tuyến .

Điều này giả định rằng các ký tự đầu vào trên thực tế là tất cả các ký tự "từ".


Ngoài ra, nếu bạn không có GNU sed hoặc nếu các ký tự đầu vào không phải là tất cả các ký tự "từ", bạn vẫn có thể đạt được mục tiêu của mình mà không cần lặp lại:

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

Điều này chỉ đơn giản là đặt osau mỗi nhân vật và sau đó loại bỏ cuối cùngo khỏi chuỗi.

Hãy thử trực tuyến .


1
Điều này giả định rằng các chuỗi đầu vào bao gồm một số Xvà không có gì khác. Cả hai giải pháp đều thất bại nếu có các nhân vật khác hiện diện ...
AnoE

@AnoE Trong mẫu thứ hai, được sửa với một thay thế đơn giản Xbởi .. Xin vui lòng xem chỉnh sửa.
Chấn thương kỹ thuật số

Không tương đương với trường hợp mà OP đưa ra. Anh ta đã đưa ra các RE chính xác mà anh ta cần (thay đổi lần xuất hiện của XX trong một chuỗi). Các phiên bản của bạn chỉ cho kết quả giống như của anh ấy cho các chuỗi đầu vào chính xác mà anh ấy đã đưa ra; không cho chuỗi đầu vào chung.
AnoE

4

Tôi đã kiểm tra nếu có bất kỳ loại cờ nào để thực hiện điều này.
Ngay cả khi hành vi đó ở đó, nó sẽ tiêu tốn nhiều tài nguyên.

Tuy nhiên, trong trường hợp sử dụng cụ thể này, có thể có biểu thức chỉ hai lần và đạt được chức năng cần thiết. tức là với 2 sedbiểu thức lặp lại .

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
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.