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

3
我不确定如何用正则表达式来实现这一点(或者我是否能够;我对正则表达式很新)。我有一个角度值,用户将输入并尝试验证该条目。它采用度-分-秒的形式。我遇到的问题是,如果用户错误地输入了秒部分,我必须捕获该错误,但我的度-分匹配是成功的。
也许方法会更好地解释:
    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;
    }
}

我想检查度分格式是否匹配,但只有当用户没有输入任何秒数数据时才这样做。我可以通过正则表达式来实现吗,还是需要解析该字符串并单独评估每个部分?谢谢。

编辑:正确的数据示例为45-23-10。问题在于45-23也是有效数据;0秒被理解为空缺。因此,如果用户意外输入了45-23-1=,我的代码中的degreeMinMatchPattern正则表达式将成功匹配,即使它是无效的。

第二次编辑:只要注意到分钟和秒钟是可选的。用户输入45也是有效的。


1
你有一些样本数据吗? - Rubens Farias
这是45-23-1=。我想你可能没看到等号。也许一个更好的例子是45-23-1A。对于造成的困惑,我很抱歉。 - Shawn
5个回答

4
您可以使用{m,}语法指定“模式的这一部分至少匹配3次”。由于每个组件之间都有连字符,因此需要单独指定第一部分,然后每个连字符-数字组合可以在之后分组匹配。
`[0-9](-[0-9]){2,}`

您也可以将 [0-9] 缩写为 \d\d(-\d){2,}

我认为他想匹配2个或3个数字,但如果后面跟着无效输入,则仅匹配2个数字,而不是跟着其他内容时。 - Tim Pietzcker

2
首先,正则表达式中的一个字符默认只匹配一次,因此 {1} 是多余的。
其次,由于您显然可以隔离这个值(您提示仅为此值而提供提示,而不必在输入的数据段中查找它),因此应将 ^ 和 $ 包含在字符串中,以强制该字符串仅包含此模式。
尝试 "^\d{1,3}-\d{1,2}(-\d{1,2})?$"。
分解一下:^ 匹配字符串的开头。 \d 匹配任何单个十进制字符,然后在其后面指定 {1,3},它将匹配任何数字的一到三次出现。然后您正在寻找一个破折号,然后是类似的十进制模式,但仅出现一次或两次。最后一个术语被括在括号中,以便我们可以对字符进行分组。它的形式与前两个类似,然后有一个 ?,它将前面的字符组标记为可选。 结尾处的 $ 表示输入应该结束。鉴于此,它将匹配 222-33-44 或 222-33,但不会匹配 222-3344 或 222-33-abc。
请记住,您可能需要合并其他规则。例如,秒可以表示为小数(如果您需要比一秒更小的分辨率)。您需要选择性地期望小数点和一个或多个其他数字。此外,您可能有一个最大度数值;上述正则表达式将匹配最大整数 DMS 值 359-59-59,但它还将匹配无效的 999-99-99。您可以使用正则表达式限制最大值(例如,“(3 [0-5] \ d | [1-2] \ d {2} | \ d {1,2})”将匹配从 0 到 359 的任何数字,通过匹配 3,然后是 0-5,然后是 0-9,或任何以 1 或 2 开头的 3 位数字,或任何两位数字),但是正如示例所示,正则表达式会变得冗长而混乱,因此请在代码中对其进行良好的文档记录。

通过轻微修改(因为三个中的第二个也是可选的,而C#需要第二个反斜杠来正确转义d),这个代码可以工作。我的最终表达式是"^\d{1,3}(-\d{1,2}(-\d{1,2})?)?$"。谢谢! - Shawn
如果您在打开字符串的双引号前加上一个@符号,.NET将自动转义任何需要转义的字符。这对于文件(反斜杠目录分隔符)和多行数据(\ r \ n everywhere)以及正则表达式非常有用。 - KeithS
今天我还学到了另外一件事情(我知道多行数据,但不知道正则表达式)。谢谢! - Shawn

1
也许你最好将输入解析出来,逐个检查每一部分。

0

我不确定我理解得是否正确,但我认为

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

可能有效。但这个有点模糊;而且我想知道为什么你只允许单位为一位数的度/分/秒值。请给出一些你希望匹配和不希望匹配的示例。

0

也许你应该尝试这样做,并测试空/无效的组:

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

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