首页 > 解决方案 > 正则表达式:确认可选部分是否匹配

问题描述

我有一个可以有两种形式的字符串,不知道每次都是哪种形式:

hello world[0:10];或者hello world;

可能有也可能没有带数字的括号。这两个词(你好和世界)可能会有所不同。如果有括号和数字,则第一个数字始终为 0,而第二个数字 (10) 会有所不同。

我需要捕获第一个单词 (hello),如果存在,则捕获第二个数字 (10)。我还需要知道它是哪种形式的字符串。

hello world[0:10];我会捕获 {hello, 10, form1},hello world;我会捕获 {hello, form2}。我并不关心“表单”的格式,我只需要能够区分。它可能有点(1=form1, 0=form2),结构(form1 将我置于一个范围,而 form2 将我置于另一个范围)等。


我目前有以下(现在正在工作)正则表达式:

/(\w*) \s \w* (?:\[0:(\d*)\])?;/x

这给了我$1 = hello和潜在$2 = 10的。我现在只需要知道括号中的数字是否存在。这将重复很多次,所以我不能假设$2 = undef进入正则表达式。$2也可能连续几次是同一件事,所以我不能只$2在正则表达式之前和之后寻找变化。

到目前为止,我最好的解决方案是运行正则表达式两次,第一次使用括号,第二次没有:

if( /(\w*) \s \w* \[0:(\d*)\];/x ) {...}
elsif( /(\w*) \s \w*;/x ) {...}

这似乎非常低效和不优雅,所以我想知道是否有更好的方法?

标签: regexperl

解决方案


您可以使用?选择性地匹配您的正则表达式的部分。然后,您可以直接将输出捕获为正则表达式的返回值。

my $re = qr{ (\w*) \s* (?:\[0:(\d+)\])?; }x;
if( my($word, $num) = $line =~ $re ) {
    say "Word: $word";
    say "Num: $num" if defined $num;
}
else {
    say "No match";
}

(?:\[0:(\d+)\])?可能[0:\d+](?:)使分组不被捕获,因此仅\d+被捕获。

$1并且$2使用起来也很安全,它们在每次匹配时都会重置,但是使用词法变量会使事情更加明确。


推荐阅读