2013-09-27 243 views
6

Tôi cần đánh dấu mọi từ trùng lặp trong văn bản có ký hiệu *.
Ví dụThực hiện lệnh trên cùng một dòng nhiều lần với sed

lol foo lol bar foo bar 

nên

lol foo *lol* bar *foo* *bar* 

Tôi đã thử với các lệnh sau:

echo "lol foo lol bar foo bar" | sed -r -e 's/(\b[a-zA-Z]+\b)([^*]+)(\1)/\1\2*\3*/' 

Nó mang lại cho tôi:

lol foo *lol* bar foo bar 

Sau đó, tôi đã thêm 012.cờ:

lol foo *lol* bar foo *bar* 

Nhưng foo không được tô sáng.
Tôi biết điều đó xảy ra vì seddoesn't look behind if the match was found.

Tôi có thể xử lý chỉ với sed không?

+1

Chỉ có 'sed' bạn nói ... Điều này sẽ yêu cầu một số thuật sĩ' sed' tôi tin. – rid

+0

Tại sao không sử dụng 'awk'? Nó có thể giải quyết vấn đề của bạn. – Jotne

+0

@ Jotne thẳng thắn nói rằng tôi đã có nhiệm vụ để làm điều đó với chỉ sed. Nhưng nói chung tôi đã quan tâm nếu 'sed' có thể thực hiện cùng một lệnh trên một dòng nhiều lần – Dany

Trả lời

4

Sed không phải là công cụ tốt nhất cho tác vụ này. Nó không nhìn về phía trước, nhìn phía sau và quantifiers không tham lam, nhưng đưa ra một thử với lệnh sau:

sed -r -e ':a ; s/\b([a-zA-Z]+)\b(.*) (\1)(|$)/\1\2 *\3*/; ta' 

Nó sử dụng có điều kiện phân nhánh để thực hiện lệnh thay cho đến khi nó bị lỗi. Ngoài ra, bạn không thể kiểm tra ([^*]+) vì vòng thứ hai nó phải đi qua một số * của thay thế đầu tiên, tùy chọn của bạn là tham lam .*. Và cuối cùng, bạn không thể đối sánh (\1) chỉ vì nó sẽ khớp với chuỗi đầu tiên lol lặp đi lặp lại. Bạn cần một số bối cảnh như được bao quanh bởi dấu cách hoặc cuối dòng.

Sản lượng lệnh:

lol foo *lol* bar *foo* *bar* 

CẬP NHẬT: Một cải tiến được cung cấp bởi potong trong ý kiến:

sed -r ':a;s/\b(([[:alpha:]]+)\s.*\s)\2\b/\1*\2*/;ta' file 
+0

+1 rực rỡ ... đó là thuật sĩ! – iamauser

+0

@Birei vâng, đây là phép thuật, nó phù hợp với tôi! bạn có thể giải thích lệnh 'a' và' ta' trong trường hợp này không? – Dany

+0

Một cải tiến nhỏ (vì giải pháp này có thể giới thiệu thêm một khoảng trống ở cuối dòng khi từ cuối cùng là một sự lặp lại) là: 'sed-r': a; s/\ b (([[: alpha:]] +) \ s. * \ s) \ 2 \ b/\ 1 * \ 2 * /; ta 'tập tin'. N.B. Nếu bạn chèn lệnh 'l0' ngay trước lệnh' ta', bạn sẽ thấy sed làm phép thuật của nó. – potong

1

Sử dụng awk

awk '{for (i=1;i<=NF;i++) if (a[$i]++>=1) printf "*%s* ",$i; else printf "%s ",$i; print ""}' file 
lol foo *lol* bar *foo* *bar*