仅当实例出现一次时,正则表达式匹配

时间:2017-04-15 11:31:39

标签: c# regex

我想在C#中为我的规则创建一个Regex验证。我有以下规则:

  

@N [货币] [签字]大小[签字] [货币]

  • 货币:([$]|[~][^~]*[~])?
  • 签署:-
  • 尺寸:[1-9][0-9]*(仅限尺寸)

这是正则表达式:[@][nN]([$]|[~][^~]*[~])?-?[1-9][0-9]*-?([$]|[~][^~]*[~])?

我的问题是货币和标志只能在尺寸的左侧或右侧出现一次。这意味着如果标志已经在尺寸左侧,则不应再出现在右侧,货币也是如此。

使用正则表达式可以做到这一点吗?

以下内容应符合:

  • @ N $ 7-
  • @ N-7 $
  • @ N $ -7
  • @ N7 - $

以下匹配:

  • @ N $ 5 $
  • @ N $ -5 -
  • @ N-5 -

3 个答案:

答案 0 :(得分:2)

我不知道C#是否支持条件表达式,但如果支持,则可以使用:

\@[nN](\$)?(-)?[1-9]\d*(?(2)|-)(?(1)|\$)(?:\s|$)

<强>解释

\@[nN]      : @ followed by n case insensitive
(\$)?       : optional $ sign captured in group 1
(-)?        : optional minus sign captured in group 2
[1-9]\d*    : value
(?(2)|-)    : if group 2 exists then nothing, else minus sign
(?(1)|\$)   : if group 1 exists then nothing, else $ sign
(?:\s|$)    : a space or end of line

以下是perl脚本示例:

use Modern::Perl;

my $re = qr~\@[nN](\$)?(-)?[1-9]\d*(?(2)|-)(?(1)|\$)(?:\s|$)~;
while(<DATA>) {
    chomp;
    say (/$re/ ? "OK: $_" : "KO: $_");
}
__DATA__
@N$7-
@N-7$
@N$-7
@N7-$
@N$5$
@N$-5-
@N-5-
@N7$-
@N-$7

<强>输出:

OK: @N$7-
OK: @N-7$
OK: @N$-7
OK: @N7-$
KO: @N$5$
KO: @N$-5-
KO: @N-5-
KO: @N7$-
KO: @N-$7

答案 1 :(得分:2)

您可以使用构造^(?!.*pattern.*pattern)禁止重复模式。对于您的情况,正则表达式如下所示:

(?mx)^
(?!.*([$]|~[^~]*~).*([$]|~[^~]*~))
(?!.*-.*-)
@[nN]([$]|~[^~]*~)?-?[1-9][0-9]*-?([$]|~[^~]*[~])?$

正则表达式演示:https://regex101.com/r/YBhQPB/1

C#demo:https://dotnetfiddle.net/8jG3y4

答案 2 :(得分:2)

如果您对使用C#运行其他测试的正则表达式解决方案没问题,可以编写一个简单的方法来验证两个组中只有一个捕获值:

static bool HasOnlyOne(Match m, int g1, int g2) {
    if (!m.Success) {
        return false;
    }
    var has1 = m.Groups[g1].Success;
    var has2 = m.Groups[g2].Success;
    return !has1 || !has2;
}

使用此功能,您可以使用略微修改版本的正则表达式执行以下测试:

var r = new Regex(
    @"^[@][nN]([$]|[~][^~]*[~])?(-)?[1-9][0-9]*(-)?([$]|[~][^~]*[~])?$"
    //                          ^ ^            ^ ^
);
string s;
while ((s = Console.ReadLine()) != null) {
    var m = r.Match(s);
    bool good = HasOnlyOne(m, 1, 4) && HasOnlyOne(m, 2, 3);
    if (good) {
        Console.WriteLine("Match: {0}", s);
    } else {
        Console.WriteLine("Fail: {0}", s);
    }
}

Demo.

我在评论中使用^标记对您的正则表达式进行了修改。