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

bar*_*lop 37 linux command-line sed

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

如果是这样,怎么样?

Pau*_*ce. 29

Parentheses can be used for grouping alternatives. For example:

sed 's/a\(bc\|de\)f/X/'
Run Code Online (Sandbox Code Playgroud)

says to replace "abcf" or "adef" with "X", but the parentheses also capture. There is not a facility in sed to do such grouping without also capturing. If you have a complex regex that does both alternative grouping and capturing, you will simply have to be careful in selecting the correct capture group in your replacement.

Perhaps you could say more about what it is you're trying to accomplish (what your need for non-capturing groups is) and why you want to avoid capture groups.

Edit:

There is a type of non-capturing brackets ((?:pattern)) that are part of Perl-Compatible Regular Expressions (PCRE). They are not supported in sed (but are when using grep -P).

  • @barlop:啊!现在我明白了你的目标.`(?:)`样式非捕获括号是[Perl-Compatible Regular Expressions](http://linux.die.net/man/3/pcrepattern)(PCRE)的一部分,`sed`不支持(但是在'grep -P`中). (3认同)
  • 只是我原则上是老式的,希望能够通过不需要捕获的非捕获括号来减少开销。并且还想知道 sed 是否可以做到这一点以及如何做到这一点,只是想知道。几个月前,我确实进行了一次正则表达式测验,当不需要捕获时,坚持使用非捕获括号,但它没有使用 sed!它使正则表达式看起来更混乱(?:不那么容易看,但我认为这是放弃测验作者认为可能正确的好习惯 (2认同)

bar*_*lop 11

答案是,在写作时,你不能 - 不支持它.Sed支持BRE和ERE,但不支持PCRE.

(注意 - 一个答案指出BRE也称为POSIX sed,ERE是通过sed -r的GNU扩展.点仍然是sed不支持PCRE.)

对于Windows或Linux,Perl可以工作

这里的例子

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
Run Code Online (Sandbox Code Playgroud)

虽然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>
Run Code Online (Sandbox Code Playgroud)

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

它有一个非常好的语法.

要使用的标准内容是perl,或者几乎任何其他人们使用的编程语言.


Sie*_*geX 7

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

默认情况下,sed将按( )字面意思进行解释,而不尝试对其进行反向引用。您需要对它们进行转义以使它们变得特殊,就像\( \) 只有当您使用 GNUsed -r选项时转义才会被逆转。对于sed -r,非转义( )将产生反向引用,而转义\( \)将被视为文字。示例如下:

POSIXsed

$ 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/'
(###)
Run Code Online (Sandbox Code Playgroud)

GNUsed -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
Run Code Online (Sandbox Code Playgroud)

更新

来自评论:

不存在仅组、非捕获括号( ),因此您可以使用间隔之类的东西{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
Run Code Online (Sandbox Code Playgroud)