Как работает string.split( "\\ S" )
Я делал вопрос из книги oracle_certified_professional_java_se_7_programmer_exams_1z0-804_and_1z0-805 Ганеша и Шармы.
Один вопрос:
-
Рассмотрим следующую программу и предскажите результат:
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 подстрок (первая - ""
, а последняя - " "
).