代码之家  ›  专栏  ›  技术社区  ›  Shawn

匹配[0-9]-[0-9]-[0-9]的模式,但不匹配[0-9]-[0-9]

  •  3
  • Shawn  · 技术社区  · 14 年前

    我不知道如何用正则表达式(或者如果可以的话,我是新来的regex)来实现这一点。我有一个角度值,用户将输入,我正在尝试验证输入。它的形式是度分秒。我遇到的问题是,如果用户输入错误的秒数部分,我必须捕捉到这个错误,但是我的学位-分钟匹配是成功的。

    也许这种方法能更好地解释:

        private Boolean isTextValid(String _angleValue) {
    
            Regex _degreeMatchPattern = new Regex("0*[1-9]");
            Regex degreeMinMatchPattern = new Regex("(0*[0-9]-{1}0*[0-9]){1}");
            Regex degreeMinSecMatchPattern = new Regex("0*[0-9]-{1}0*[0-9]-{1}0*[0-9]");
    
            Match _degreeMatch, _degreeMinMatch, _degreeMinSecMatch;
    
            _degreeMinSecMatch = degreeMinSecMatchPattern.Match(_angleValue);
            if (_degreeMinSecMatch.Success)
                return true;
    
            _degreeMinMatch = degreeMinMatchPattern.Match(_angleValue);
            if (_degreeMinMatch.Success)
                return true;
    
            _degreeMatch = _degreeMatchPattern.Match(_angleValue);
            if (_degreeMatch.Success)
                return true;
    
            return false;
        }
    }
    

    如果度-分-秒匹配不成功,我想检查度-分,但仅当用户没有输入任何秒数据时。我可以通过regex来实现这一点,还是需要分别分析字符串和计算每个部分?谢谢。

    编辑:样本数据将是45-23-10作为正确的数据。问题是45-23也是有效数据;0秒可以理解。因此,如果用户意外地键入45-23-1=on,那么代码中的degreeminMatchPattern regex将成功匹配,即使它是无效的。

    第二次编辑:为了清楚起见,分钟和第二部分都是可选的。用户可以键入45,这是有效的。

    5 回复  |  直到 14 年前
        1
  •  2
  •   KeithS    14 年前

    首先,正则表达式中的字符默认匹配一次,因此1是多余的。

    其次,由于您可以很明显地隔离这个值(您只提示输入这个值,而不必在输入数据的段落中查找它),所以您应该在字符串中包含^和$以强制字符串只包含这个模式。

    试试“^\d 1,3-\d 1,2(-\d 1,2)”?$”。

    分解:^匹配字符串的开头。\ d匹配任何一个十进制字符,然后在后面指定1,3,它将匹配一组1到3次出现的任何数字。然后你要找的是一个破折号,然后是一个类似的十进制模式,但只有一到两次。最后一个术语用括号括起来,这样我们可以对字符进行分组。它的形式和前两个相似,然后有一个?它将前面的字符组标记为可选。末尾的$表示输入应该结束。鉴于此,它将匹配222-33-44或222-33,但不匹配222-3344或222-33-ABC。

    请记住,您可能还需要加入其他规则。例如,秒可以表示为十进制(如果您希望分辨率小于1秒)。您需要有选择地期望小数点和一个或多个附加数字。另外,您可能有一个最大度值;上面的regex将匹配DMS值359-59-59的最大整数,但是它也将匹配999-99-99,这是无效的。您可以使用regex限制最大值(例如“(3[0-5]\d[1-2]\d 2 \d 1,2)”,通过匹配3、0-5、0-9或以1或2或任何两位数字开头的任何3位数字,或任何两位数字),但如示例所示,regex将变得冗长而混乱,因此doc在代码中很好地说明你在做什么。

        2
  •  4
  •   Ether    14 年前

    您可以使用 {m,} 语法。由于每个组件之间都有连字符,请分别指定第一个部分,然后每个连字符数字组合可以在以下时间后组合在一起:

    `[0-9](-[0-9]){2,}`
    

    你也可以缩短 [0-9] \d : \d(-\d){2,}

        3
  •  1
  •   Steven Sudit    14 年前

    也许您最好只分析输入输出,并单独检查。

        4
  •  0
  •   Tim Pietzcker    14 年前

    我不确定我是否理解正确,但我想

    (?<degrees>0*[0-9])-?(?<minutes>0*[0-9])(?:-?(?<seconds>0*[0-9]))?$
    

    可能有用。

    但这是非常含糊的;我也在想为什么你只允许一位数的度/分/秒的值。请给出一些你想做和不想做匹配的例子。

        5
  •  0
  •   Rubens Farias    14 年前

    也许您应该尝试这样的方法并测试空组/无效组:

    Regex degrees = new Regex(
                    @"(?<degrees>\d+)(?:-(?<minutes>\d+))?(?:-(?<seconds>\d+))?");
    string[] samples = new []{ "123", "123-456", "123-456-789" };
    foreach (var sample in samples)
    {
        Match m = degrees.Match(sample);
        if(m.Success)
        {
            string degrees = m.Groups["degrees"].Value;
            string minutes = m.Groups["minutes"].Value;
            string seconds = m.Groups["seconds"].Value;
            Console.WriteLine("{0}°{1}'{2}\"", degrees,
                String.IsNullOrEmpty(minutes) ? "0" : minutes,
                String.IsNullOrEmpty(seconds) ? "0" : seconds
            );
        }
    }