如何在Perl正则表达式中使用可选匹配项?

时间:2009-06-05 16:25:07

标签: regex perl

我有一个从配置文件中读取的字符串。字符串的结构如下;

(long_string)long_string(long_string)

括号中的任何项目(包括括号本身)都是可选的。我有以下正则表达式匹配整个字符串,但我无法弄清楚如何使用“?”使正则表达式的某些部分可选。

以下是一些有效的输入字符串

(a)like(1)
like(very long string here)
like

这是我的正则表达式只匹配第一个;

^\((?<short>.*)\)(?<text>.*)\((?<return>.*)\)$

如何将我的正则表达式转换为匹配可选括号?

5 个答案:

答案 0 :(得分:5)

使用不匹配的群组(?: expr )围绕这两个子模式并将其设为可选:

^(?:\((?<short>.*)\))?(?<text>.*)(?:\((?<return>.*)\))?$

如果可能的话,使通用表达式.*更具体,可能使用[^()]+

^(?:\((?<short>[^()]+)\))?(?<text>[^()]+)(?:\((?<return>[^()]+)\))?$

答案 1 :(得分:4)

使用下面的代码,您将始终获得一个由三个元素组成的@matches数组。如果其中一个可选部件不匹配,则相应的条目将为undef。

#!/usr/bin/perl

use strict;
use warnings;

my $optional = qr/(?:\(([^)]+?)\))?/;
my $required = qr/([^()]+)/;

while ( my $line = <DATA> ) {
    chomp $line;
    last unless $line =~ /\S/;

    if ( my @matches = ($line =~ /$optional$required$optional/) ) {
        no warnings 'uninitialized';
        print "---$_---\n" for @matches;
    }
}

__DATA__
(a)like(1)
like(very long string here)
like

答案 2 :(得分:1)

我要做的是用你的分组成员包装(和),而不是

\((?<short>.*)\)

将其更改为:

(\(<short>.*\))

这样它会匹配()和内部文本。然后,如果它们存在则使用另一个正则表达式来消除括号。

我对命名匹配语法不是很熟悉,所以组语法可能会关闭,但您应该明白这一点。

答案 3 :(得分:0)

试一试......

string[] strings = new string[] { "(a)like(1)", "like(very long string here)", "like" };
foreach (string s in strings)
{
    System.Text.RegularExpressions.Match match = System.Text.RegularExpressions.Regex.Match(s, @"^(\((?<short>.)\))?(?<text>.+)?(\((?<return>.+)\))?$");
    if (match.Success)
    {
        // do logic to handle the match
    }
}

答案 4 :(得分:0)

好吧,只需将它们作为可选项,然后:

^(?<short>\(.*\))?(?<text>.*)(?<return>\(.*\))?$

我不喜欢命名的捕获,它们往往使它看起来比它复杂(至少对我而言)。另外,我建议不要使用“.*”。我的建议是:

^(\([^)]*\))?([^(]*)(\([^)]*\))?$

然后去匹配组2.但是如果你坚持使用命名捕获:

^(?<short>\([^)]*\))?(?<text>[^(]*)(?<return>\([^)]*\))?$