解析一串空格分隔,排序但可选的元素

时间:2010-09-12 22:03:18

标签: java regex

这是我想要解决的具体问题的概括。

给定一串由单个空格分隔的唯一可识别元素:

0 1 2 3 4

如果没有修改字符串,当任何一个数字是可选的,除了一个数字和数字是有序的,那么正则表达式会匹配这个表达式吗?

其他有效字符串的示例:

2
0 4
1 4
0 1 2 3
0 1 3 4
0 1 2 3 4

4 个答案:

答案 0 :(得分:3)

正则表达式可能不是最好的工具。如果您可以使用前瞻,那么您可以通过以下示例进行管理:

^(?=0? ?1? ?2? ?3? ?4?$)(?:\d )*\d$

Rubular

说明:

^                       Match the start of line/string.
(?=0? ?1? ?2? ?3? ?4?$) Look ahead to restrict to 0 to 4 in that order.
(?:\d )*\d              Ensure that the string is alternating digit then space.
$                       Match the end of line/string.

将它概括为固定长度的字符串,所有长度都相等,使得读取起来稍微困难一些。例如,对于ab ba cd de ef,它将如下所示:

^(?=(?:ab)? ?(?:ba)? ?(?:cd)? ?(?:de)? ?(?:ef)?$)(?:\w{2} )*\w{2}$

Rubular


但是将它推广到不同长度的单词会变得更加混乱,例如zero one two three four你可以使用这个正则表达式:

^(?=(?:zero)? ?(?:one)? ?(?:two)? ?(?:three)? ?(?:four)?$)(?! )(?: ?(?:zero|one|two|three|four)(?= |$))+$

Rubular

答案 1 :(得分:1)

我强烈支持从元模式中编程生成正则表达式模式(另请参阅Martin Fowler's argument for using composed regex)。该技术非常适用于这种情况。

这是Java中的解决方案:

static String orderedOptional(String sep, String... items) {
    StringBuilder sb = new StringBuilder();
    for (String item : items) {
        sb.append(
            "(?:item(?:sep(?!$)|$))?"
                .replace("item", item)
                .replace("sep", sep)
        );
    }
    return sb.toString();
}
static String wholeLineNonEmpty(String pattern) {
    return "^(?!$)pattern$".replace("pattern", pattern);
}

现在我们有(as seen on ideone.com):

    String PATTERN =
        wholeLineNonEmpty(
            orderedOptional(" ",
                "one", "two", "three")
        );

    String[] tests = {
        "",                 // false
        "onetwo",           // false
        "one two",          // true
        "one two ",         // false
        "two three",        // true
        "three",            // true
        "one three",        // true
        "one two three",    // true
        "three two one"     // false
    };
    for (String test : tests) {
        System.out.println(test.matches(PATTERN));
    }

还可以轻松地将orderedOptional元模式与其他分隔符和项目一起使用,也可以在没有wholeLineNonEmpty元模式的情况下使用它。这是一个例子:

    String INCREASING_DIGITS = 
        wholeLineNonEmpty(
            orderedOptional("[,;]",
                "1", "2", "3", "4", "5", "6", "7", "8", "9")
        );
    System.out.println(INCREASING_DIGITS);
    // ^(?!$)(?:1(?:[,;](?!$)|$))?(?:2(?:[,;](?!$)|$))?(?:3(?:[,;](?!$)|$))?
    // (?:4(?:[,;](?!$)|$))?(?:5(?:[,;](?!$)|$))?(?:6(?:[,;](?!$)|$))?
    // (?:7(?:[,;](?!$)|$))?(?:8(?:[,;](?!$)|$))?(?:9(?:[,;](?!$)|$))?$

此模式接受例如"9""1;2,4""2,3"并拒绝,例如"""4321""4;3;2;1""1;"see on rubular.com)。毫无疑问,最终的模式看起来很丑陋,难以理解,但这就是为什么它首先以编程方式生成,使用更容易理解的简单模式和自然自动化的过程。

答案 2 :(得分:0)

没有正则表达式能够验证语言的顺序,除非为可接受的有序集合的每个组合指定表达式。您应该查看pushdown automata解决方案。

答案 3 :(得分:0)

正则表达式不足以解决任意输入字符串的问题。对于任何set输入字符串,您可以通过列出所有可能匹配的字符串来明显构建正则表达式,但这很愚蠢。在任何现代高级语言中,这个问题应该是微不足道的,所以让我们知道你正在使用的语言。