Как работает string.split( "\\ S" )

Я делал вопрос из книги oracle_certified_professional_java_se_7_programmer_exams_1z0-804_and_1z0-805 Ганеша и Шармы.

Один вопрос:

  1. Рассмотрим следующую программу и предскажите результат:

      class Test {
    
        public static void main(String args[]) {
          String test = "I am preparing for OCPJP";
          String[] tokens = test.split("\\S");
          System.out.println(tokens.length);
        }
      }
    

    a) 0

    b) 5

    c) 12

    d) 16

Теперь я понимаю, что \S - средство регулярных выражений, которое обрабатывает непространственные символы как разделители. Но я был озадачен тем, как выражение регулярного выражения выполняет его соответствие, и каковы фактические жетоны, произведенные расколом.

Я добавил код для распечатки токенов следующим образом

for (String str: tokens){
  System.out.println("<" + str + ">");
}

и я получил следующий вывод

16

<>

< >

<>

< >

<>

<>

<>

<>

<>

<>

<>

<>

< >

<>

<>

< >

Так много пустых токенов. Я просто не понимаю этого.

Я бы подумал по строкам, что если разделители не являются пробелами, то в приведенном выше тексте все алфавитные символы служат разделителями, поэтому, возможно, должно быть 21 токен, если мы сопоставим которые также приводят к пустым строкам. Я просто не понимаю, как работает Java regex engine. Есть ли какие-либо гуру регулярных выражений, которые могут пролить свет на этот код для меня?

Ответ 1

Первые вещи начинаются с \s (нижний регистр), который является символьным классом регулярного выражения для пробела, то есть пробелами '' tabs '\ t', новыми строками '\n' и '\ r' вертикальная вкладка '\ v' и множество других символов.

\s (верхний регистр) является противоположностью этого, так что это будет означать любой символ небелого пробела.

Итак, когда вы разделите эту строку "I am preparing for OCPJP" с помощью \s, вы эффективно разбиваете строку на каждую букву. Причина, по которой ваш маркерный массив имеет длину 16.

Теперь о том, почему они пусты.

Рассмотрим следующую строку: Hello,World, если бы мы разделили ее, используя ,, мы получим массив String длины 2 со следующим содержимым: Hello и World. Обратите внимание, что , не находится ни в одной из строк, он был удален.

То же самое произошло с I am preparing for OCPJP String, оно было разделено, а точки, соответствующие вашему регулярному выражению, не находятся ни в одном из возвращаемых значений. И поскольку за большинством букв в этой строке следует другая буква, вы получаете нагрузку строк с нулевой длиной, сохраняются только символы пробела.

Ответ 2

Скопировано из API документация: (выделены жирным шрифтом)

public String[] split(String regex)

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

Например, строка "boo: and: foo" дает следующие результаты: с этими выражениями:

 Regex  Result
   :    { "boo", "and", "foo" }
   o    { "b", "", ":and:f" }

Проверьте второй пример, когда последние 2 "o" просто удалены: ответ на ваш вопрос "OCPJP" подстрока рассматривается как коллекция разделителей, которая не выполняется для непустых строк, так что часть обрезается.

Ответ 3

В результате результат равен 16, а не 21, из javadoc для Split:

Таким образом, конечные пустые строки не включаются в массив.

Это означает, например, что если вы скажете

"/abc//def/ghi///".split("/")

результат будет иметь пять элементов. Первый будет "", так как это не конечная пустая строка; остальные будут "abc", "", "def" и "ghi". Но оставшиеся пустые строки удаляются из массива.

В опубликованном случае:

"I am preparing for OCPJP".split("\\S")

это то же самое. Поскольку символы без пробелов являются разделителями, каждая буква является разделителем, но буквы OCPJP по существу не учитываются, поскольку эти разделители приводят к завершению пустых строк, которые затем отбрасываются. Итак, поскольку в "I am preparing for" имеется 15 букв, они рассматриваются как разграничение 16 подстрок (первая - "", а последняя - " ").