regex - 组的可选令牌似乎阻止捕获?
问题描述
我想捕获 X{} 和 Y{} 括号之间的文本:
echo "example ,X{whateverX},...,Y{whateverY} the end" | \
perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\}).*(,Y\{(.*?)\})/;'
whateverX whateverY
现在,我想让 X 和/或 Y 的存在成为可选的,但是一旦我添加了可选修饰符,它就会停止匹配/捕获:
echo "example ,X{whateverX},...,Y{whateverY} the end" | \
perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\})?.*(,Y\{(.*?)\})?/;'
<nothing printed>
注意:上面我添加了?每个 X/Y 组的 和 修饰符,如下所示(最后一个字符):
.\*(,X\\{(.\*?)\\})**?**
.\*(,Y\\{(.\*?)\\})**?**
例如,这里我只有 Y 作为可选,并且只有 X 匹配:
echo "example ,X{whateverX},...,Y{whateverY} the end" | \
perl -ne 'print "$2 $4 \n" if /.*(,X\{(.*?)\}).*(,Y\{(.*?)\})?/;'
whateverX
我希望这三个都能产生“whateverX whateverY”,但只有第一个会......
我错过了什么?为什么将捕获组设为可选会破坏我的匹配?
解决方案
您应该提醒自己正则表达式的基本方面:只要整个表达式可以匹配,它们默认是贪婪的。
你的例子
/.*(,X\{(.*?)\})?.*(,Y\{(.*?)\})?/
只有可选元素,所以它总是匹配 - 一个空字符串,如果没有别的。
问题是,RE 会在尽可能早的位置和最大可能的位置上贪婪(同时仍然能够匹配表达式的其余部分)。因此,第一个.*
将消耗字符串中的所有内容,而其他子表达式默认匹配空字符串(通过?
或*
)。
很难让 X{} 和 Y{} 成为可选,同时仍然希望它们存在;如果您将它们设为可选,那么正则表达式引擎将最终不会使用它们,如果它可以逃脱的话。
我建议使用子表达式,其中 X{} 和 Y{} 的交替组合出现在内部(?:...|...)
(随后根据使用的分支将值分配给变量)或内部分支重置(?|...|...)
(编写为正确的代码以使用/x
):
use strict;
use warnings;
foreach my $data (<DATA>) {
chomp $data;
if ($data =~ /
(?|
.*? # both X and Y present
,X \{ ([^{}]*) \}
.*?
,Y \{ ([^{}]*) \}
|
.*? # only X present
,X \{ ([^{}]*) \}
.*
()
|
.*? # only Y present
()
,Y \{ ([^{}]*) \}
|
() () # neither X nor Y present
)
/x) {
print "$1, $2\n";
}
}
exit 0;
__DATA__
example ,X{whateverX},...,Y{whateverY} the end
example2 ,X{whateverX2},random data to the end
example3 with data before ,Y{whateverY3} the end
example4 with just data and no separators
将输出:
whateverX, whateverY
whateverX2,
, whateverY3
,
请注意,前导.*?
's 是必需的,否则()()
在每种情况下最终都会匹配。
推荐阅读
- css - 调整大小后图像有空白
- xml - 如何以这样一种方式创建 XSD 定义:如果字段为空,JAXB 从此类 XSD 创建的类将生成带有空 xml 标记的 xml
- javascript - React Native - 无法在其他屏幕中显示数据
- javascript - 用分隔值在另一个(主)数组中创建一个数组
- c# - 如何在 WPF 数据网格单元格编辑模式下使用 myCustomTextBox 更改文本框
- c++ - 这个数字去除算法的正确最大运行时间是 O(1) 还是 O(n)?
- ios - 如何确保我的 for in 循环使我只能执行一个 segue?
- android - 如何在不使用意图的情况下传递 HashMap 值?
- javascript - .eslintignore 没有忽略我的目录
- angular - 如何解决“从角度发布数据集合时出现空值问题”?