如何使用 sed 匹配 2 个或 3 个冒号?

How can I match 2 or 3 colons using sed?

我正在研究正则表达式组,但遇到了一些困扰我的问题。鉴于以下内容:

TestEko:::Test
TestEko::Test

我无法匹配冒号组。我试过以下方法:

\(::\|:::\)  # only matches ::
\(:\{2,3\}\) # only matches ::
\(::\+\)     # only matches ::

那么,如何匹配第一行的 ::: 和第二行的 ::

如果你想在这里匹配任意数量的冒号,请尝试使用下面的表达式

s/(:)+/*/g

这会将任意数量的冒号替换为 *

你的输出将是

TestEko* Test
TestEko* Test

这可能适合您 (GNU sed):

sed 's/:::\?/X&X/' file # should print TestEkoX:::XTest and TestEkoX::XTest

每种工具处理正则表达式的方式都略有不同。甚至 sed 也有不同的方式,因为 sed 有多种实现方式。

如果你在 Linux,你可能是 运行 GNU sed,它会做你想做的事而不需要太多额外的努力:

$ printf 'one::two\nthree:::four\n' | sed 's/:::\?/_/'
one_two
three_Four

但是,在 FreeBSD 中,您使用的是 BSD sed,它的工作方式与 GNU 不同。在 FreeBSD 中,以下工作(类似于您的尝试之一):

$ printf 'one::two\nthree:::four\n' | sed 's/:\{2,3\}/_/'
one_two
three_four

当然,如果您使用 Extended RE 而不是 sed 的默认 Basic RE 表示法,所有这些都会得到简化。 (您可以 man re_format 了解更多相关信息。)

在 Linux 和 FreeBSD 中,这有效:

$ printf 'one::two\nthree:::four\n' | sed -r 's/:::?/_/'
one_two
three_four

在 FreeBSD 和 OSX 中,这有效:

$ printf 'one::two\nthree:::four\n' | sed -E 's/:::?/_/'
one_two
three_four

是的,FreeBSD 支持扩展 RE 的 -r-E-E 选项是多年前引入的,OSX 将 BSD 源代码用于他们自己的版本。较新的 FreeBSD 版本添加了 -r 以与 GNU sed 兼容,但 OSX 尚未采用该版本。

当然,我应该指出所有这些都受到影响,因为它们没有锚定到任何一侧的非冒号字符。所以从技术上讲,如果你只搜索 ::,你也会匹配 ::::

printf 'one::two\nthree:::four\n' | sed -r 's/::/_/'
one_two
three_:four

所以您需要一些方法来识别 "not colon" 字符。您不能使用单词分隔符([[:<:]][[:>:]]),因为这不是单词边界,但这应该有效:

$ printf 'one::two\nthree:::four\nfive::::six\n' | sed -r 's/([^:])(:::?)([^:])/_/'
one_two
three_four
five::::six

即使在 BRE 中:

printf 'one::two\nthree:::four\nfive::::six\n' | sed 's/\([^:]\):\{2,3\}\([^:]\)/_/'
one_two
three_four
five::::six  

这有帮助吗?