正则表达式:将具有相同内容的组解释为单个组

Regex: Interpret groups with the same content as a single group

我有以下情况:

^ID[ \t]*=[ \t]*('(.*)'|"(.*)")

有内容的群

01

当文件包含:

ID = '01'

是第二个。
相反,如果:

ID = "01"

第三个。

这给我带来了 perl 的问题:

perl -lne "print $2 if /^ID[ \t]*=[ \t]*('(.*)'|\"(.*)\")/" test.txt

如果带单引号的组匹配,那么我得到输出:

01

否则我得到一个空字符串。

如何在正则表达式中将单引号和双引号都解释为第二组?

您可以打印这两个组,因为它们永远不会同时匹配:

perl -lne "print $2.$3 if /^ID[ \t]*=[ \t]*('(.*)'|\"(.*)\")/" 

或者记住 $2 中的引号并将 $3 用于带引号的字符串,然后是记住的引号:

perl -lne "print $3 if /^ID[ \t]*=[ \t]*((['\"])(.*))/"

只会定义两者之一,因此只需使用已定义的那个即可。

perl -nle'print // if /^ID\h*=\h*(?:\x27(.*)\x27|"(.*)")/'   # \x27 is '

您也可以使用反向引用。

perl -nle'print  if /^ID\h*=\h*(["\x27])(.*)/'

请注意,如果您有 ID="abc\"def"ID="abc\ndef" 之类的内容,则包括这两个在内的所有提供的解决方案都会失败(保留转义序列),假设它们受支持。

这看起来很适合 branch reset operator(?|...)。该交替中的任一捕获是 </code>,而 branch-reset 构造负责分组而不捕获任何内容:</p> <pre><code>use v5.10; my @strings = qw( ID='01' ID="01" ID="01'); foreach ( @strings ) { say if m/^ID \h* = \h* (?|'(\d+)'|"(\d+)") /x }

您需要 v5.10,这样您就可以使用 \h 来匹配水平空格。

但是,您不需要重复该模式。您可以匹配报价并稍后匹配相同的报价。一个relative backreference\g{N},可以做到:

use v5.10;

my @strings = qw( ID='01' ID="01" ID="01' );

foreach ( @strings ) {
    say  if m/^ID \h* = \h* (['"])(\d+)\g{-2} /x
    }

我更喜欢 \g{-2} 因为如果我更改模式以在引用的内容之前包含更多捕获,我通常不必更新编号。

而且,因为这是 one-liner,所以不要输入引号(正如 ikegami 已经展示的那样):

    say  if m/^ID \h* = \h* ([\x22\x27])(\d+)\g{-2} /x

谢谢@brian_d_foy:

perl -lne "print $1 if /^ID\h*=\h*(?|'(.*)'|\"(.*)\")/" test.txt

或更好:

perl -lne "print $2 if /^ID\h*=\h*(['\"])(.*)/" test.txt

我决定也接受

ID = 01 #Followed by one or more horizontal spaces.

除了:

ID = "01" #Followed by one or more horizontal spaces.

并且:

ID = '01' #Followed by one or more horizontal spaces.

因此我采用了一个超级复杂的解决方案:

perl -lne "print $2 if /^ID\h*=\h*(?|(['\"])(.*)|(([^\h'\"]*)))\h*(?:#.*)?$/" test.txt

我已经融合了你的两个解决方案@brian_d_foy。双圆括号也用于将第二个选项也带到第二组,否则它将是第一组,甚至没有“分支重置运算符”,它将是第 4 组。

我在函数中增强了 sintax

function parse-config {
    command perl -pe "s/\R/\n/g" "" | command perl -lne "print $2 if /^\h*=\h*(?|(['\"])(.*)|(([^\h'\"]*)))\h*(?:#.*)?$/"
    return $?
}
parse-config "ID" "test.txt"

在此:

"s/\R/\n/g"

我在LF中替换了所有CRLF或CR或LF。 \R 是 perl v5.10 中出现的一个超级强大的特殊字符。显然,这个版本的 perl 为我引入了几个基本的创新。有可能我需要所有 (\h \R ?|)。更新的人太棒了。
我需要这个,因为行尾的美元“$”不起作用,因为在“Linux 行尾”“\n”之前有一个“\r”。