【问题标题】:Perl regex: why is the optional part not captured?Perl 正则表达式:为什么未捕获可选部分?
【发布时间】:2020-08-11 12:26:05
【问题描述】:

我正在尝试捕获最后一部分是可选的匹配项,但如果存在则应该捕获。但如果使用(...)? 是可选的,则不会被捕获。

例如,使用以下 2 行:

some text and number 18
some other text

我想总是捕捉“一些”,如果我看到“数字 18”,就捕捉“18”。

使用/(some).*?(?:number (\d+))/,当然适用于第一行,但不适用于第二行:

$ echo "some text and number 18" | perl -nle '/(some).*?(?:number (\d+))/ && print join("\n", $1, $2)'
some
18
$ echo "some other text" | perl -nle '/(some).*?(?:number (\d+))/ && print join("\n", $1, $2)'
$

但是当使用/(some).*?(?:number (\d+))?/ 使最后一部分可选时,总是捕获第一个匹配项,但数量不是:

$ echo "some text and number 18" | perl -nle '/(some).*?(?:number (\d+))?/ && print join("\n", $1, $2)'
some

$ echo "some other text" | perl -nle '/(some).*?(?:number (\d+))?/ && print join("\n", $1, $2)'
some

$ 

如何捕获可选部分?

【问题讨论】:

  • (some) 匹配位置 [0,4) 的 4 个字符,.*? 匹配位置 [4,4) 的 0 个字符,(?:number (\d+))? 匹配位置 [4,4) 的 0 个字符.

标签: regex perl


【解决方案1】:

你可以使用

/(some)(?:.*?number (\d+))?/

请参阅regex demo。详情:

  • (some) - 第 1 组:some
  • (?:.*?number (\d+))? - 一个可选的非捕获组,将至少尝试一次,并将尝试匹配 1 次或 0 次
    • .*? - 除换行符之外的任何 0+ 字符,尽可能少
    • number - number 字符串
    • (\d+) - 第 2 组:1 位以上

查看online demo

perl -nle '/(some)(?:.*?number (\d+))?/ && print join("\n", $1, $2)' <<< "some text and number 18"
# some
# 18
perl -nle '/(some)(?:.*?number (\d+))?/ && print join("\n", $1, $2)' <<< "some other text"
# some

【讨论】:

  • 确实,将通配符部分移动到非捕获组内可以使其工作。奇怪...
  • @mivk 这是合乎逻辑的,因为整个可选组模式将至少尝试一次,? 是一个贪婪的量词。 (some).*?(?:number (\d+))? 仅在 number \d+ 紧跟在 some 之后才有效。见this demo。这是因为.*? 不必匹配,因为它是非贪婪的,正则表达式引擎会跳过它,然后去测试后续的子模式。由于(?:number (\d+))? 可以匹配模式序列的1 次或0 次出现,并且在当前位置不匹配,所以它匹配0 个字符,并调用它返回some 的有效匹配。
猜你喜欢
  • 1970-01-01
  • 2017-07-27
  • 1970-01-01
  • 2021-09-06
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多