Разделить строку с помощью регулярного выражения \ w \ w *?\ Ш +? - PullRequest
5 голосов
/ 18 марта 2012

Я изучаю регулярные выражения и думал, что начинаю понимать. но потом ...

Я попытался разбить строку, и мне нужна помощь, чтобы понять такую ​​простую вещь, как:

String input = "abcde";
System.out.println("[a-z] " + Arrays.toString(input.split("[a-z]")));
System.out.println("\\w " + Arrays.toString(input.split("\\w")));
System.out.println("\\w*? " + Arrays.toString(input.split("\\w*?")));
System.out.println("\\w+? " + Arrays.toString(input.split("\\w+?")));

The output is
[a-z] - []
\w    - []
\w*?  - [, a, b, c, d, e]
\w+?  - []

Почему ни одна из двух первых строк не разделяет строку на символ? Третье выражение \ w * ?, (знак вопроса предотвращает жадность) работает, как я и ожидал, разбивая строку на каждый символ. Звезда, ноль или более совпадений, возвращает пустой массив.

Я пробовал выражение в NotePad ++ и в программе, и оно показывает 5 совпадений, как в:

Scanner ls = new Scanner(input);
while(ls.hasNext())
    System.out.format("%s ", ls.findInLine("\\w");

Output is: a b c d e

Это действительно озадачивает меня

Ответы [ 3 ]

11 голосов
/ 18 марта 2012

Если вы разделите строку с помощью регулярного выражения, вы по сути скажете, где строка должна быть обрезана. Это обязательно отсекает то, что вы соответствуете с регулярным выражением. Это означает, что если вы разделяете на \w, то каждый символ является точкой разделения, и возвращаются подстроки между ними (все пустые). Java автоматически удаляет завершающие пустые строки, как описано в документации .

Это также объясняет, почему ленивое соответствие \w*? даст вам каждый символ, потому что оно будет соответствовать каждой позиции между (и до и после) любым символом (нулевой ширины). Осталось только символы строки.

Давайте разберемся:

  1. [a-z], \w, \w+?

    Ваша строка

    abcde
    

    И совпадения следующие:

     a  b  c  d  e
    └─┘└─┘└─┘└─┘└─┘
    

    , который оставляет подстроки между совпадениями, все из которых пусты.

    Вышеупомянутые три регулярных выражения ведут себя одинаково в этом отношении, поскольку все они будут соответствовать только одному символу. \w+? сделает это, потому что в нем отсутствуют какие-либо другие ограничения, которые могут заставить +? попытаться сопоставить больше, чем просто минимум (в конце концов, он ленив).

  2. \w*?

      a  b  c  d  e
    └┘ └┘ └┘ └┘ └┘ └┘
    

    В этом случае совпадения между символами, оставляя вам следующие подстроки:

    "", "a", "b", "c", "d", "e", ""
    

    Java выбрасывает завершающий пустой, хотя.

3 голосов
/ 18 марта 2012

Давайте разберем каждый из этих вызовов до String#split(String). Из документации Java следует заметить, что «метод работает так, как если бы он вызывал метод разбиения с двумя аргументами с заданным выражением и нулевым аргументом предельного значения. Поэтому в результирующие пустые строки не включаются массив. "

"abcde".split("[a-z]"); // => []

Этот соответствует каждому символу (a, b, c, d, e) и приводит только к пустым строкам между ними, которые опущены.

"abcde".split("\\w")); // => []

Опять же, каждый символ в строке является символом слова (\w), поэтому результатом являются пустые строки, которые опускаются.

"abcde".split("\\w*?")); // => ["", "a", "b", "c", "d", "e"]

В этом случае * означает «ноль или более предыдущего элемента» (\w), что соответствует пустому выражению семь раз (один раз в начале строки, затем один раз между каждым символом). Таким образом, мы получаем первую пустую строку, затем каждый символ.

"abcde".split("\\w+?")); // => []

Здесь + означает «один или несколько из предыдущего элемента» (\w), который соответствует всей входной строке, в результате чего получается только пустая строка, которая опускается.

Попробуйте эти примеры еще раз с input.split(regex, -1), и вы должны увидеть все пустые строки.

1 голос
/ 18 марта 2012

String.split обрезает строку при каждом совпадении шаблона:

Массив, возвращаемый этим методом, содержит каждую подстроку этой строки, которая заканчивается другой подстрокой, соответствующей данному выражению, или заканчивается концом строки.

Таким образом, всякий раз, когда образец, подобный [a-z], совпадает, строка обрезается в этом совпадении. Поскольку каждому символу в вашей строке соответствует шаблон, результирующий массив пуст (завершающие пустые строки удаляются).

То же самое относится к \w и \w+? (один или несколько \w, но как можно меньше повторений). То, что \w*? приводит к тому, что вы ожидали, связано с квантификатором *?, так как он будет совпадать с нулем повторений, если это возможно, так что пустая строка. И пустая строка находится в каждой позиции в данной строке.

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