我在用:
$ echo ".a.b.c." | awk '
{
t=gensub(/.([a-z])./,"[\\1]","g",$1); print t
}'
[a]b[c]
我想结束[a][b][c]
。我怎样才能开始gensub
处理重叠的比赛?
如果这是不可能的,我怎样才能实现这一目标?
答案1
你可以做类似的事情:
perl -pe 's{\.([a-z](?:\.[a-z])*)\.}{"[$1]" =~ s/\./][/gr}ge'
即把所有的 替换为.x.y.z.
,[x.y.z]
其中.
s 替换为][
。
同样的awk
,避免使用gensub()
gawk 特有的并且使用起来很麻烦,因为它不会让你知道它何时成功:
awk '
{
while(match($0, /(\.[abcdefghijklmnopqrstuvwxyz])+\./)) {
s = substr($0, RSTART + 1, RLENGTH - 2)
gsub(/\./, "][", s)
$0 = substr($0, 1, RSTART - 1) "["s"]" substr($0, RSTART+RLENGTH)
}
print
}'
如果使用当前版本mawk
(尚未本地化)或最新版本,gawk
或者如果在 C 语言环境中,则可以替换abcdefghijklmnopqrstuvwxyz
为a-z
.除了这些条件之外,不能保证它们是等效的。特别是,在某些语言环境中,[a-z]
每个 POSIX 旨在匹配一系列整理元素, 不是人物甚至可以匹配多个字符,就像ddzs
在匈牙利语言环境中一样。
无论如何,请注意,要匹配正则表达式中的文字点,您需要\.
或[.]
。.
否则,它本身就是一个匹配任何单个字符的正则表达式运算符。
答案2
通常正则表达式引擎不会考虑重叠匹配,这不是您建议的方式,但也不会导致后一个匹配会考虑前一个替换插入的字符。
在 Perl 中,您可以利用后视来匹配右括号的右侧,并重复替换(在整个字符串上),次数与执行的操作次数相同。在这里,假设您要匹配文字点之间的字母(正则表达式.
匹配任何单个字符):
% cat test.txt
.a.b.c.
..a..
.a.b c.d.
.a]b.
% perl -pe '1 while s/(\.|(?<=\]))([a-z])\./[$2]/' < test.txt
[a][b][c]
.[a].
[a]b c[d]
.a][b]
最后一行显示误报,其中现有]
触发以下b.
匹配。您可以通过首先插入一些不太可能出现在输入中的字节,然后用真正的括号替换它们来避免这种情况。例如字节值1,^A:
% perl -pe '1 while s/(\.|(?<=\001))([a-z])\./[$2\001/; tr/\001/]/' < test.txt
[a][b][c]
.[a].
[a]b c[d]
.a]b.
这可能还有其他我没有碰巧发现的问题。在重复替换时,如果匹配太松,则存在陷入无限循环的风险,但这不应该是一个风险,因为替换需要一个文字点并且总是删除至少一个点。
(如果您的意思是.
正则表达式中的 匹配任何字符,那么我想 egabcd
应该变成[b]d
,这看起来很奇怪。)
答案3
这是红宝石:
echo ".a.b.c." | ruby -pe '$_.gsub!(/(?:[.][a-z](?=\.))|\./){|m| m[/^\.$/] ? "" : "[#{m[1]}]" }'
或者 Perl:
echo ".a.b.c." | perl -pe 's/(?:[.]([a-z])(?=\.))|\./($1 eq "") ? "" : "[$1]" /ge'
要么打印:
[a][b][c]