只有当实例出现一次时才进行正则匹配。

3

我想在C#中为我的规则创建一个正则表达式验证。我的规则如下:

@N [货币] [符号] 大小 [符号] [货币]

  • 货币:([$]|[~][^~]*[~])?
  • 符号:-
  • 大小:[1-9][0-9]*(只有大小是必须的)

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

我的问题是,货币和符号应该只出现一次,要么在大小左边,要么在右边。这意味着如果符号已经在大小左边,则不应再在右边出现,货币也是同理。

使用正则表达式是否可能实现这个功能?

以下内容应匹配:

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

以下内容不应匹配:

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

最简单的方法是使用 ^ 和 $ 创建多个正则表达式,并将它们放在 |(或)中。 - xanatos
@dasblinkenlight @N7$- 不应匹配。因为符号必须在货币之前(根据规则)。@N-$7 也不符合规则。 - Devid
@xanatos 能否请您再解释详细一点? - Devid
你只需要一个是/否匹配,还是计划从捕获组中提取匹配值?对于你的目的,一种部分依赖于正则表达式,部分依赖于C#代码解释匹配的解决方案是否可行? - Sergey Kalinichenko
1
这是另一个使用负向前瞻的正则表达式示例:https://regex101.com/r/A1lqdj/1/。 - bobble bubble
显示剩余2条评论
3个回答

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

.NET支持条件表达式。虽然它不能满足原始规则,因为@N7也应该匹配。在https://regex101.com/上进行了测试。 - Devid

2
您可以使用构造^(?!.*pattern.*pattern)来禁止模式重复。对于您的情况,正则表达式如下所示:
(?mx)^
(?!.*([$]|~[^~]*~).*([$]|~[^~]*~))
(?!.*-.*-)
@[nN]([$]|~[^~]*~)?-?[1-9][0-9]*-?([$]|~[^~]*[~])?$

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

C#演示:https://dotnetfiddle.net/8jG3y4


我喜欢这个,因为它很容易扩展规则,而且我不知道像这样的东西是可能的。这对我来说是新的学习内容。 - Devid

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);
    }
}

演示。

我在注释中使用了^标记来标记您的正则表达式的修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接