7

我需要用*符号突出显示文本中的每个重复单词。
例如

lol foo lol bar foo bar

应该

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

我尝试使用以下命令:

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

它给了我:

lol foo *lol* bar foo bar

然后我添加了g标志:

lol foo *lol* bar foo *bar*

foo没有突出显示。
我知道它会发生,因为sed 如果找到匹配项就不会回头

我可以处理它sed吗?

4

2 回答 2

4

Sed不是完成这项任务的最佳工具。它没有前瞻、后瞻和非贪婪量词,而是尝试以下命令:

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

它使用条件分支来执行替换命令,直到它失败。此外,您无法检查([^*]+),因为对于第二轮它必须遍历一些*第一次替换,您的选择是 greedy .*。最后,你不能仅仅因为它会一次又一次(\1)地匹配第一个字符串而匹配。lol您需要一些上下文,例如被空格或行尾包围。

该命令产生:

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

更新potong在评论中提供的改进:

sed -r ':a;s/\b(([[:alpha:]]+)\s.*\s)\2\b/\1*\2*/;ta' file
于 2013-09-27T22:11:52.417 回答
1

使用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*
于 2013-09-28T05:50:54.710 回答