正则表达式检查重复

时间:2012-12-26 20:03:58

标签: c# java regex

我正在尝试使用正则表达式检查文本行。

1,3,4,5,8,10,12,14,19,14

这里的数字用','分隔,并且应该是非negetive并且小于或等于20。 并且任何数字都不应该重复。 这是我的模式。

^(?:(?:0[1-9]|[1-9]|1[0-9]|20),)*(?:0[1-9]|[1-9]|1[0-9]|20)$

但它无法检查重复。我怎么检查呢?

5 个答案:

答案 0 :(得分:7)

你想做的事情并不复杂。如果字符串中再次出现此数字,您只需要在每个匹配的数字后检查:

^(?:(0[1-9]|[1-9]|1[0-9]|20),(?!.*\b\1\b))*(?:0[1-9]|[1-9]|1[0-9]|20)$

查看并测试here on Regexr

在C#中:

string[] myStrings = { "1",
    "1,2",
    "01,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20",
    "01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20",
    "01,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,5",
    "01,02,03,04,05,06,07,08,13,09,10,11,12,13,14,15,16,17,18,19,20" };

Regex reg = new Regex(
    @"^
        (?:(0[1-9]|[1-9]|1[0-9]|20),
            (?!.*\b\1\b) # Fail if the before matched number occurs once more
        )*
        (?:0[1-9]|[1-9]|1[0-9]|20)
    $",
    RegexOptions.IgnorePatternWhitespace
);

foreach (string myString in myStrings)
    Console.WriteLine("{0} {1} a valid string.",
        myString,
        reg.IsMatch(myString) ? "is" : "is not"
    );

Console.ReadLine();

答案 1 :(得分:4)

正如你用C#和Java标记了你的问题,我不会在这里给你一个代码解决方案,但基本的想法。

如果您将字符串拆分为,,则会得到一个子字符串列表:"1", "3" , "4", "5", "8", "10", "12", "14", "19", "14"。现在,您可以循环遍历这些并尝试将每个解析为整数。如果失败,则不是数字。如果成功,您可以轻松检查它是< 0还是> 20。您还可以保留一组之前已有的数字,并检查当前的数字是否重复。

最重要的是,您不应该尝试使用所有内容的正则表达式。而且你的语言要求不是regular(如果你需要记住东西,或计算东西,通常不是常规的)。基于Perl的RegExps能够比常规更多,但这还不够。

作为正则表达式的解决方案

正如你在评论中所说,一行最多只能容纳20个数字。由于每个数字也被限制在0到20之间,因此您可以获得线条实际外观的可能性。因此,您拥有有限的语言(具有有限数量的可能行​​)。有限语言是常规语言的子集,因此,您可以“轻松地”使用正则表达式来表示语言。

最简单的解决方案是只列出每条可能的行。所以,如果你每行只有3个数字,其中5个是最高的数字(为了简单起见),正则表达式可能如下所示:

0,1,2|0,1,3|0,1,4|0,1,5|0,2,3|0,2,4|0,2,5|0,3,4|0,3,5|0,4,5|1,2,3|1,2,4|1,2,5|1,3,4|1,3,5|1,4,5|2,3,4

当然,你可以简化那么多(甚至更多):

0,(1,(2|3|4|5)|2,(3|4|5)|3,(4|5)|4,5)|1,(2,(3|4|5)|3,(4|5)|4,5)|2,(3,(4|5)|4,5)|3,4,5

但是,是的,如果你有一个要求使语言有限,它也会有规律,但不一定很漂亮;我认为“手动”解决方案仍然更具可读性,特别是更灵活。

答案 2 :(得分:2)

正则表达式不是最好的选择。对于重复数字,它太快了。您可能希望查看标记化。即使是寻找不存在的模式这样的简单事情也很困难(例如,请参阅Regular expression to match a line that doesn't contain a word?

我会用commmas拆分字符串,然后将它们添加到有序列表中。如果使用C#:

"1,2,3,4".Split(',')

开始然后继续Linq以查看您的条件是否满意。

如果您必须使用正则表达式执行此操作,请查看迭代集合搜索返回。但是这对于上面的解决方案来说很少购买。

答案 3 :(得分:1)

String[] numbers = input.split(",");
Set<Integer> filtered = new TreeSet();

for(String number: numbers) {
   if(!number.startsWith("-") {
      int nbr = Integer.parseInt(number);

      if(nbr < 20) {
         filtered.add(nbr);
      }
   }
}
for(int nbr: filtered) {
   System.out.print(nbr + " ");
}

答案 4 :(得分:0)

既然你想要正则表达式,是的,你将受到后向引用的限制,因为它们只从\ 1到\ 9。所以你需要排除配对。你最大的挑战是摆脱重复的数字。

来自http://www.regular-expressions.info/refadv.html

(?:(\d?\d),?)+(?!<regex>)一起使用,以确保您没有重复项。您也可以使用 (?(?=<regex>)true|false)

我使用此页面进行实验:http://www.regextester.com/