4

问题

我有一个文件充满了像

convert.these.dots.to.forward.slashes/but.leave.these.alone/i.mean.it

我想搜索和替换这样我得到

convert/these/dots/to/forward/slashes/but.leave.these.alone/i.mean.it

这 。转换为 / 直到第一个正斜杠

问题

如何编写正则表达式搜索和替换来解决我的问题?

尝试的解决方案

我尝试在 perl 中使用look behind,但是没有实现可变长度的look behinds

$ echo "convert.these.dots.to.forward.slashes/but.leave.these.alone/i.mean.it" | perl -pe 's/(?<=[^\/]*)\./\//g'
Variable length lookbehind not implemented in regex m/(?<=[^/]*)\./ at -e line 1.

解决方法

实现了可变长度前瞻,因此您可以使用这个肮脏的技巧

$ echo "convert.these.dots.to.forward.slashes/but.leave.these.alone/i.mean.it" | rev | perl -pe 's/\.(?=[^\/]*$)/\//g' | rev
convert/these/dots/to/forward/slashes/but.leave.these.alone/i.mean.it

这个问题有更直接的解决方案吗?

4

2 回答 2

5
s/\G([^\/.]*)\./\1\//g

\G是一个与前一个匹配结束时的点匹配的断言。这确保了每个连续的匹配紧跟最后一个。

火柴:

\G          # start matching where the last match ended
([^\/.]*)   # capture until you encounter a "/" or a "."
\.          # the dot

替换为:

\1     # that interstitial text you captured
\/     # a slash

用法:

echo "convert.these.dots.to.forward.slashes/but.leave.these.alone/i.mean.it" | perl -pe 's/\G([^\/.]*)\./\1\//g'

# yields: convert/these/dots/to/forward/slashes/but.leave.these.alone/i.mean.it

或者,如果你是一个纯粹主义者并且不想重新添加捕获的子模式——避免这样做可能更有效,但我不确定——你可以使用\K将“真实”匹配限制为仅., 然后简单地替换为/. \K本质上“忘记”了到目前为止匹配的内容,因此最终返回的最终匹配只是\K.

s/\G[^\/.]*\K\./\//g

火柴:

\G        # start matching where the last match ended
[^\/.]*   # consume chars until you encounter a "/" or a "."
\K        # "forget" what has been consumed so far
\.        # the dot

因此,匹配替换的整个文本只是“ .”。

替换为:

\/      # a slash

结果是一样的。

于 2013-04-19T00:58:27.697 回答
2

您可以将substr其用作左值并对其执行替换。或音译,就像我在下面所做的那样。

$ perl -pe 'substr($_,0,index($_,"/")) =~ tr#.#/#'
convert.these.dots.to.forward.slashes/but.leave.these.alone/i.mean.it
convert/these/dots/to/forward/slashes/but.leave.these.alone/i.mean.it

这会找到斜杠的第一个实例,提取它之前的字符串部分,并对该部分执行音译。

于 2013-04-19T01:02:51.693 回答