【问题标题】:java regex input shorter than patternjava正则表达式输入比模式短
【发布时间】:2013-10-25 12:15:29
【问题描述】:

通过使用正则表达式,我试图在用户输入时验证用户输入。

我的模式是这样的:"(\\w{3})(\\d{7})(\\w{3})". 有效的输入可以是"XYZ0001112CCC"

我想验证它作为用户类型。我的意思是"A", "AB", "ABC", "ABC12", "ABC123", ..., "ABC1234567XY" 也不应该失败。但是"A1", "AB2", "ABCD123", ..., "ABC1234567XY1" 必须失败。只要输入不违反规则,我想假设它“到目前为止有效”。正则表达式可以做到这一点吗?

【问题讨论】:

    标签: java regex matcher


    【解决方案1】:

    我会在第一个字母之后的每个后续部分使用“一次或根本不”量词的组合,并向后看以验证输入的前面部分。

    例如:

    //                           |first letters (1 to 3)
    //                                        | if 3 letters precede...
    //                                                         | digits (1 to 7)
    //                                                                   | if 7 digits precede...
    //                                                                               | 3 letters
    Pattern p = Pattern.compile("[a-zA-Z]{1,3}((?<=[a-zA-Z]{3})\\d{1,7})?((?<=\\d{7})[a-zA-Z]{3})?");
    String[] inputs = {"XYZ0001112CCC", "A", "AB", "ABC", "ABC12", "ABC123", "A1", "AB2", "ABCD123","ABC1234567XY1"};
    Matcher m;
    for (String input: inputs) {
        m = p.matcher(input);
        System.out.println("Input: " + input + " --> Matches? " + m.matches());
    }
    

    输出:

    Input: XYZ0001112CCC --> Matches? true
    Input: A --> Matches? true
    Input: AB --> Matches? true
    Input: ABC --> Matches? true
    Input: ABC12 --> Matches? true
    Input: ABC123 --> Matches? true
    Input: A1 --> Matches? false
    Input: AB2 --> Matches? false
    Input: ABCD123 --> Matches? false
    Input: ABC1234567XY1 --> Matches? false
    

    注意

    我已将您的\\w 表达式更改为字符类[a-zA-Z],因为\\w 也可以验证数字。 [a-zA-Z] 的替代品是:

    • \\p{Alpha}
    • [a-z] 带有 Pattern.CASE_INSENSITIVE 标志

    最后说明

    我的Pattern 将最后一个字母作为一个 3 字母组。 如果您还接受 1 或 2 个字母,则只需将最后一个量词表达式 {3} 更改为 {1,3}

    【讨论】:

    • 为什么 ABC12 或 ABC123 返回 false?
    • @Tim 我的错,我在第一个 3 个字母之后的整个输入中使用了“一次或根本没有”量词。固定。
    • 谢谢@Mena。现在看来还可以。我对正则表达式不太熟悉。但是您是否建议在这种情况下使用正则表达式?它可以工作,但在性能方面也可以。这是正则表达式使用的方便情况吗?
    • @Tim 我认为正则表达式对此没问题,在这种情况下,实际的 Pattern 没有那么多开销(您可能希望将其编译为常量 --> static final每次重新编译它)。在这种情况下,根据正则表达式的复杂性,它并不复杂。例如,看看那里的一些电子邮件验证模式...... 那些很复杂;)
    【解决方案2】:

    您可以将模式更改为更简单的模式([a-zA-Z]+)(\d+)([a-zA-Z]+)

    然后你可以检查每个组中有多少个字母:

    Pattern p = Pattern.compile("([a-zA-Z]+)(\d+)([a-zA-Z]+)");
    Matcher matcher = p.matcher("ABC1234567XYZ");
    if (matcher.find()) {
        String firstLetters = matcher.group(1);
        String digits = matcher.group(2);
        String lastLetters = matcher.group(3);
    
        //any checks here
    }
    

    【讨论】:

    • IllegalStateException: 未找到匹配项。
    • 奇怪的是它没有找到匹配项。我还更新了模式,因为 \w 也需要下划线 + 数字,并且 + 是至少一场比赛所必需的。
    • 我认为您建议的模式必须是:([a-zA-Z]*)(\\d*)([a-zA-Z]*)。这也是一个很好的解决方案,但 Mena 的解决方案对我来说似乎更好,因为所有检查都是在正则表达式中完成的。
    【解决方案3】:

    我建议您将验证拆分为两个单独的正则表达式:一个用于valid-so-far 验证,另一个用于最终检查。

    即便如此,验证这一点并非易事,例如ABC1 目前有效。像(\\w{0,3})(\\d{0,7})(\\w{0,3}) 这样的模式不会削减它,因为 X0C 会被错误地认为是有效的。因此,我建议您不要尝试仅使用正则表达式来解决此问题,而应使用一些编码逻辑。

    (可以使用lookbehindsif-then-else conditionals 将所有验证逻辑压缩到一个正则表达式中,但我建议不要这样做。它不可读且不可维护。)

    【讨论】:

    • 您有什么“迄今为止有效”的建议吗?不会有很多可能吗?
    • @Tim 您可以将所有内容放入一个正则表达式中,就像 Mena 在他的回答中显示的那样,尽管您必须自己判断您是否接受这种复杂性。
    【解决方案4】:

    由于格式相当简单,你可以这样做(我不知道确切的 java 语法,但我认为这个想法很清楚):

    String input = "DEF3";
    String example = "ABC1234567XY";
    Pattern regex = Pattern.compile("(\\w{3})(\\d{7})(\\w{3})");
    
    String test_input = input + example.last_digits(example.length-input.length);
    Matcher matcher = p.matcher(test_input);
    return matcher.find();
    

    这样你唯一的重复是在示例和正则表达式之间。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-29
      • 1970-01-01
      • 2017-05-26
      • 1970-01-01
      • 1970-01-01
      • 2012-03-19
      • 2016-04-24
      相关资源
      最近更新 更多