我需要使用 sed 做类似的事情吗?
qq ab xyz ab qq aa ab
变成:
qq ab xyz +ab+ +qq+ aa +ab+
答案1
如果您的输入不包含<
,>
也不+
包含字符,您可以这样做:
sed '
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g'
如果可以的话,你总是可以逃避它们:
sed '
s/:/::/g;s/</:{/g;s/>/:}/g
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g
s/:}/>/g;s/:{/</g;s/::/:/g'
这些假设您想在每一行上独立地执行此操作。如果您想对整个文件执行此操作,则需要首先将整个文件加载到内存中(请注意,某些sed
实现有大小限制):
sed '
:2
$!{N;b2
}
s/:/::/g;s/</:{/g;s/>/:}/g
s/[[:alnum:]]\{1,\}/<&>/g;:1
s/\(<\([^>]*\)>.*\)<\2>/\1+\2+/;t1
s/[<>]//g
s/:}/>/g;s/:{/</g;s/::/:/g'
但这会非常低效,并且使用以下命令会容易得多perl
:
perl -pe 's/\w+/$seen{$&}++ ? "+$&+" : $&/ge'
基于线路:
perl -pe 'my %seen;s/\w+/$seen{$&}++ ? "+$&+" : $&/ge'
答案2
这是另一种方法:这使用了一些sed
s:
an='[:alnum:]' esc=$(printf '\033\[')
sed "/[${an}]/!d;=;a\ }
s/.*/ & /;s/[^${an}]\{1,\}/ /g
s| \([${an}"']\{1,\}\) | \
s/\\([^+'"${an}"']\\)\\(\1\\)\\([^+'"${an}"']\\)/\\1+\\2+\\3/2|g
' <text |
sed '/^ /!N;s/\n */{/' |
sed -e 's/.*/ & /;s/+/ & /g' \
-f - \
-e "s/ //;s/ $//
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
s/ + /+/g" text
基本上,前两个sed
团队合作为第三个编写剧本。第一个sed
清除每行中除字母数字字符之外的所有内容 - 并完全跳过任何没有行的行。对于剩下的所有字符组,它会编写一个替换语句,第三个字符最终将(几乎是瞬间)阅读并解释其脚本。
第二个sed
是必要的,因为第一个按行编写脚本 - 并且每行可以有多个s///
语句。第一个打印包含字母数字的每一行的行号,但需要在第三个的函数上下文中配对sed
- 所以第二个这样做。
以下是脚本的示例:
...
43{
s/\([^+[:alnum:]]\)\(n\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(N\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(G\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
44{
s/\([^+[:alnum:]]\)\(b\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(block\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
45{
s/\([^+[:alnum:]]\)\(END\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(SEDSCRIPT\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
2
每个都有一个尾随s///
- 这是因为每个替换都是针对每个模式的第二次出现 - 如果第二次出现不存在,则不会进行任何替换。上面是在我的另一个sed
脚本上运行它的结果 - 它似乎不受特殊字符或类似字符的影响。
当我写作时,我发现如果我给它的选择着色,就更容易知道发生了什么 - 这就是......
s/+[^+ ]\{1,\}+/${esc}38;5;35m&${esc}0m/g
...那条线确实如此。您可以评论或删除它(您曾经使用过它并且不想要或不需要它)。
这是它为示例数据编写的脚本:
1{
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(xyz\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(qq\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(aa\)\([^+[:alnum:]]\)/\1+\2+\3/2
s/\([^+[:alnum:]]\)\(ab\)\([^+[:alnum:]]\)/\1+\2+\3/2
}
以下是其打印内容:
qq ab xyz +ab+ +qq+ aa +ab+
sed
以及我之前的一些脚本:
s/\(\(.\)${bs}\2\)\{1,\}/${esc}38;5;35m&${+esc+}0m/g
s/\(_${bs}[^_]\)\{1,\}/${esc}38;5;75m&${+esc+}0m/g
s/.${bs}//g
s/\(\(${esc}\)0m\2[^m]*+m+[_ ]\{,+2+\}\)\{+2+\}/_/g
n; /./!N;G