正则表达式:将具有相同内容的组解释为单个组
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”。
我有以下情况:
^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”。