Разбор строки, разделенных пробелами, упорядоченных, но необязательных элементов - PullRequest
2 голосов
/ 13 сентября 2010

Это обобщение конкретной проблемы, которую я пытаюсь решить.

Учитывая строку уникально идентифицируемых элементов, разделенных одним пробелом:

0 1 2 3 4

Без изменения строки,какое регулярное выражение будет соответствовать этому выражению, когда любое из чисел является необязательным, кроме одного, а числа расположены по порядку?

Примеры других допустимых строк:

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

Ответы [ 4 ]

3 голосов
/ 13 сентября 2010

Регулярные выражения могут быть не лучшим инструментом для этого.Для примера, который вы привели, можно справиться, если вы можете использовать lookaheads:

^(?=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 голос
/ 13 сентября 2010

Я убежденный сторонник программной генерации шаблонов регулярных выражений из мета-шаблонов (см. Также Аргумент Мартина Фаулера об использовании составного регулярного выражения ). Техника очень применима в этой ситуации.

Вот решение на 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);
}

Теперь у нас есть ( как видно на 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;" ( см. На rubular.com ). Без сомнения, полученный шаблон выглядит уродливым и трудным для понимания, но именно поэтому он был сгенерирован в первую очередь программно, с использованием более простых шаблонов, которые гораздо легче понять, и процесса, который естественным образом автоматизирован.

0 голосов
/ 13 сентября 2010

Регулярные выражения недостаточно мощны, чтобы решить эту проблему для произвольных входных строк. Для любой заданной входной строки вы можете создать регулярное выражение, перечислив все возможные подходящие строки, но это глупо. Эта проблема должна быть почти тривиальной на любом современном языке высокого уровня, поэтому сообщите нам, какой язык вы используете.

0 голосов
/ 13 сентября 2010

Нет регулярного выражения, которое сможет проверять порядок языка , если только вы не укажете выражение для каждой приемлемой комбинации упорядоченного набора.Вы должны взглянуть на решение с автоматом .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...