【问题标题】:Java 8: RegExp - range with various separatorsJava 8:RegEx - 具有各种分隔符的范围
【发布时间】:2018-06-27 23:02:10
【问题描述】:

我正在寻找一个正则表达式来验证以下模式:

ABC

注意:这里的 ABC 不是正则表达式,而是用于简单地描述问题

Block | Accepted values              |
------+------------------------------+
A     | Any number between 1 and 11  |
B     | , or - or |                  |
C     | Any number between 1 and 11  |

评论

  1. , : 列举了一些确切的值
  2. - : 表示范围
  3. | :一个值或另一个
  4. 这些符号可以混合使用(例如2,3 | 1-9 | 10-11

示例

有效表达式

1
9,10
9,10,11|1-5
1-11
8|10
1|3|7
etc..

无效的表达式

0
20
9,10,15
1-19
1|12
1|11,
etc..

试过

public class RuleTest {

    String A = "[1-9]|1[0-1]";
    String B = "[\\,\\-\\|]";
    String C = "[1-9]|1[0-1]";

    Pattern RULE_DROP_DIGIT = Pattern.compile(A+"|"+A+B+C);

    @Test
    public void mustPassRuledropdigitPatternTest() {
        assertTrue(RULE_DROP_DIGIT.matcher("1").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("1-9").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("10-11").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("1|9").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("10|11").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("1,9").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("10,11").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("9,10,11|1-5").matches());
        assertTrue(RULE_DROP_DIGIT.matcher("3|5|7").matches());
    }

    @Test
    public void mustFailRuledropdigitPatternTest() {
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, ""));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "  "));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "0"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "14"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1--9"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1--19"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "10--11"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1||9"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1||19"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "10||11"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1,,9"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "1,,19"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "10,,11"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "0,1"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "12"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, "8,"));
        assertTrue(catchedAssertionError(RULE_DROP_DIGIT, ",8"));
    }

    /*
     * Catch AssertionError
     */
    private boolean catchedAssertionError(Pattern code, CharSequence input) {
        try {
            assertTrue(code.matcher(input).matches());
            return false;
        } catch (AssertionError e) {
            // NOTHING
        }
        return true;
    }
}

问题

  1. 我的正则表达式有什么问题?
  2. 什么是正确的?

EDIT1:更正了 A、B EDIT2:添加注释

【问题讨论】:

  • 有点奇怪A = "[1-9]|[1-9]1[0-1]" - 为什么是第二个[1-9]
  • 抱歉打错了。最初是[1-9]|1[0-1]。已更正。谢谢!
  • 你说你想匹配模式 ABC 但似乎你允许 AABCBCBC。您要匹配的高级结构是什么?如果要允许任意数量的 B,为什么要区分 AC
  • 在您必须通过的模式测试中,很少有无效输入,例如 3|5|7 、9,10,11|1-5 甚至数字 19。这些预计会通过吗?
  • @HeyStackExchange,也许是A(BA)*?根据 RegExp 运算符优先级,A|ABC+ 指定序列(AABCABCCABCCC、...)。

标签: java regex


【解决方案1】:

您将无法使用正则表达式检查范围的左侧小于或等于右侧。

也就是说:

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

来自

String A = "(?:0*(?:1[01]|[1-9]))";
String B = "[,\\-|]";

Pattern.compile("^" + A + "(?:" + B + A + ")*$");

推导:

A     | Any number between 1 and 11  |
0*(?:1[01]|[1-9])
B     | , or - or |                  |
[,\-|]
C     | Any number between 1 and 11  |
0*(?:1[01]|[1-9])

在您的原始代码中:

String A = "[1-9]|[1-9]1[0-1]";

第二个[1-9] 将导致它不匹配 10 或 11,但会匹配 110 和 911 之间的许多数字。

另外,请注意,当未显式匹配 ^...$(例如使用 .find() 而不是 .matches())时,首先使用 [1-9] 将导致它仅匹配 11 中的第二个 '1' .

Pattern RULE_DROP_DIGIT = Pattern.compile(A+"|"+A+B+C);

ABC 没有括号,因此 "|"A 中的 | 处于同一级别。

解决此问题的一种方法是添加括号。

Pattern RULE_DROP_DIGIT = Pattern.compile("(?:"+A+")|(?:"+A+B+C+")");

【讨论】:

  • 单元测试在第一个断言处失败(assertTrue(RULE_DROP_DIGIT.matcher("1").matches()) 尽管转义了分隔符
  • @HeyStackExchange,我调整了分隔符和右数可选。
  • 谢谢。它非常接近解决方案,我可以从中工作。所以投了赞成票。但是9,10,11|1-53|5|7等表达式不会通过验证。
  • @HeyStackExchange,根据我们对您问题的讨论,我重写以允许任意数量的 BC 对。
  • 非常感谢。像魅力一样工作标记为已回答
猜你喜欢
  • 2019-01-30
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 2016-07-04
  • 1970-01-01
  • 2020-06-13
  • 1970-01-01
相关资源
最近更新 更多