如何在 sed 中指定非捕获组?

Posted

技术标签:

【中文标题】如何在 sed 中指定非捕获组?【英文标题】:how do you specify non-capturing groups in sed? 【发布时间】:2011-06-16 23:15:14 【问题描述】:

是否可以在 sed 中指定非捕获组?

如果是这样,怎么做?

【问题讨论】:

我知道文字和分组捕获之间交替的含义,基于它们是否被转义,以及是否 -r 反转它。 据我所知没有 sed 支持非捕获组。但是,Perl 很容易获得,如果您真的需要它们,它可能是正确的答案。 @TobySpeight 是的,你是对的 【参考方案1】:

括号可用于对备选方案进行分组。例如:

sed 's/a\(bc\|de\)f/X/'

表示用“X”替换“abcf”“adef”,但括号捕获。 sed 中没有工具可以在不捕获的情况下进行此类分组。如果您有一个复杂的正则表达式,它同时进行替代分组捕获,您只需小心选择替换中的正确捕获组。

也许您可以多说一下您要完成的工作(您对非捕获组的需求是什么)以及为什么要避免捕获组。

编辑:

有一种非捕获括号 ((?:pattern)) 是 Perl-Compatible Regular Expressions (PCRE) 的一部分。 sed 不支持它们(但在使用 grep -P 时支持)。

【讨论】:

只是我在原则上过时了,希望能够在不需要捕获的情况下使用非捕获括号来减少开销。并且还想知道 sed 是否可以做到以及如何做到,只是想知道。几个月前我确实经历过一次正则表达式测验,它坚持在不需要捕获时不捕获括号,但它没有使用 sed!它使正则表达式看起来更混乱(?:看起来不那么容易,但我想这是为了放弃测验作者认为可能正确的好习惯 @barlop:啊!现在我明白你的意思了。 (?:) 样式的非捕获括号是 Perl-Compatible Regular Expressions (PCRE) 的一部分,sed 不支持(但在 grep -P 中)。 @barlop 你应该把你的答案换成丹尼斯。虽然我的最终回答了你的问题,但它以一种非常复杂的方式回答了。【参考方案2】:

答案是,在撰写本文时,您不能 - sed 不支持它。

非捕获组具有(?:a) 的语法并且是PCRE 语法。

Sed 支持 BRE(基本正则表达式),也称为 POSIX BRE,如果使用 GNU sed,则有选项 -r 使其支持 ERE(扩展正则表达式),即 POSIX ERE,但仍不支持 PCRE)

Perl 适用于 windows 或 linux

这里的例子

https://superuser.com/questions/416419/perl-for-matching-with-regular-expressions-in-terminal

例如这是来自 Windows 中的 cygwin

$ echo -e 'abcd' | perl -0777 -pe 's/(a)(?:b)(c)(d)/\1/s'
a

$ echo -e 'abcd' | perl -0777 -pe 's/(a)(?:b)(c)(d)/\2/s'
c

有一个适用于 Windows 的程序,它可以在命令行上进行搜索和替换,并且支持 PCRE。它被称为 rxrepl。它当然不是 sed,但它确实支持 PCRE 进行搜索和替换。

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(c)" -r "\1"
a

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(c)" -r "\3"
c

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(b)(?:c)" -r "\3"
Invalid match group requested.

C:\blah\rxrepl>echo abc | rxrepl -s "(a)(?:b)(c)" -r "\2"
c

C:\blah\rxrepl>

作者(不是我)在这里的回答中提到了他的程序https://superuser.com/questions/339118/regex-replace-from-command-line

它的语法非常好。

使用的标准东西是 perl,或者人们使用的几乎任何其他编程语言。

【讨论】:

不知道为什么你要添加一个链接到一个只针对 Windows 的问题的答案标记为 Linux,但我猜不管你的船是什么... ;)【参考方案3】:

我假设您说的是反向引用语法,它是括号 ( ) 而不是括号 [ ]

默认情况下,sed 将按字面意思解释( ),而不是尝试从它们中进行反向引用。您需要对它们进行转义以使它们像\( \) 中那样特别。只有当您使用GNU sed -r 选项时,转义才会被逆转。对于sed -r,未转义的( ) 将产生反向引用,而转义的\( \) 将被视为文字。示例如下:

POSIX sed

$ echo "foo(###)bar" | sed 's/foo(.*)bar/@@@@/'
@@@@

$ echo "foo(###)bar" | sed 's/foo(.*)bar/\1/'
sed: -e expression #1, char 16: invalid reference \1 on `s' command's RHS
-bash: echo: write error: Broken pipe

$ echo "foo(###)bar" | sed 's/foo\(.*\)bar/\1/'
(###)

GNU sed -r

$ echo "foo(###)bar" | sed -r 's/foo(.*)bar/@@@@/'
@@@@

$ echo "foo(###)bar" | sed -r 's/foo(.*)bar/\1/'
(###)

$ echo "foo(###)bar" | sed -r 's/foo\(.*\)bar/\1/'
sed: -e expression #1, char 18: invalid reference \1 on `s' command's RHS
-bash: echo: write error: Broken pipe

更新

来自cmets:

仅组,非捕获括号 ( ),因此您可以使用类似间隔 n,m 而无需创建反向引用 \1 不存在。首先,间隔不是 POSIX sed 的一部分,您必须使用 GNU -r 扩展来启用它们。一旦启用-r,任何分组括号也将被捕获以供反向引用使用。例子:

$ echo "123.456.789" | sed -r 's/([0-9]3\.)2/###/'
###789

$ echo "123.456.789" | sed -r 's/([0-9]3\.)2/###\1/'
###456.789

【讨论】:

谢谢,但是非文字分组非捕获呢?它在哪里说 -r 是 GNU 而默认(-e?)是 POSIX?我认为默认(-e?)是 BRE,-r 是 ERE。我猜两者都是带有 GNU 的 POSIX。 另外,关于您对我的术语的评论。我认为术语括号可能意味着圆形或方形或卷曲,而不仅仅是您所说的方形。 -r 选项是 GNU 扩展。它不是POSIX sed syntax 的一部分。 -e 标志允许您内联指定多个 sed 脚本,它与 BRE 与 ERE 没有任何关系。例如echo "foo" | sed -e 's/foo/bar/' -e 's/bar/baz/' 感谢您的回答,它包含有趣的信息,但是当我说非捕获括号时,我的意思也不是文字括号,我的意思是非捕获分组括号。 @barlop RE:括号术语。我不会说调用( )“括号”肯定是错误的,但我会说,大体上常见的术语如下:括号[],括号(),大括号。 Wikipedia 似乎也支持这一点(见最右边的图片一半)。【参考方案4】:

如前所述,sed 中不可能有非捕获组。 这可能很明显,但非捕获组不是必需的。人们可以只使用所需的捕获,而忽略不想要的,就好像它们没有捕获一样。作为参考,嵌套捕获组按“(”的位置顺序编号。

例如,

echo "apple and bananas and monkeys" | sed -r "s/((apple|banana)s?)/\1x/g"

applex 和香蕉sx 和猴子(注意:香蕉中的“s”,第一个更大的组)

echo "apple and bananas and monkeys" | sed -r "s/((apple|banana)s?)/\2x/g"

applex、bananax 和猴子(注意:香蕉中没有“s”,第二小组)

【讨论】:

你说的很明显,很明显非捕获组不是绝对必要的,你仍然可以使用捕获组,但忽略捕获的内容。捕获主要只是一个额外的潜在好处,尽管一个人不必使用它。尽管如此,perl 仍然提供非捕获括号。没有人声称非捕获括号提供了一些没有它们就无法完成的重要功能。您在这里写信只是为了纠正一个没有人有的想象中的误解。 你写“这很明显。我并不是要“纠正”。只是添加它以防像我这样健忘的人认为需要使用 perl 或类似的东西来进行任何非捕获目的。” 你是对的。我编辑了答案,只是留下了评论嵌套编号组如何编号的示例,这再次很明显。如果您认为最好删除答案,我会这样做。谢谢 Hector 实际上,答案的一部分很重要,否则就不清楚你的意思是什么。另一件可能更清楚的事情是您使用 sed 的示例,因为所有与 sed 一起使用的反斜杠无论如何我首先主要是查看您的答案的英文。我会包括关于计数的那部分,因为这使答案非常清楚。您可以通过使用sed -r 简化您的 sed 示例以减少反斜杠,从而使答案更清晰。 完成。感谢您的建议。

以上是关于如何在 sed 中指定非捕获组?的主要内容,如果未能解决你的问题,请参考以下文章

在 sed 中捕获组

使用 sed 在捕获组内替换

具有捕获组的有效正则表达式,但 sed 脚本不起作用

如何在记事本++替换中分隔正则表达式组号?

如何在 AWS CDK 中指定源安全组 ID?

在 Shell 脚本中捕获命名组