如何使用 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
这有帮助吗?
我正在研究正则表达式组,但遇到了一些困扰我的问题。鉴于以下内容:
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
这有帮助吗?