Почему «split» в пустой строке возвращает непустой массив? - PullRequest
86 голосов
/ 11 февраля 2011

Разделение на пустую строку возвращает массив размера 1:

scala> "".split(',')
res1: Array[String] = Array("")

Учтите, что это возвращает пустой массив:

scala> ",,,,".split(',')
res2: Array[String] = Array()

Пожалуйста, объясните:)

Ответы [ 8 ]

63 голосов
/ 11 февраля 2011

Если вы разделите апельсин на ноль раз, у вас будет ровно одна часть - апельсин.

40 голосов
/ 11 февраля 2011

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

36 голосов
/ 13 июня 2016

Методы разделения Java и Scala работают в два этапа:

  • Сначала разбейте строку по разделителю. Естественным следствием этого является то, что если строка не содержит разделитель, возвращается массив синглтона, содержащий только входную строку,
  • Во-вторых, удалить все крайние правые пустые строки. По этой причине ",,,".split(",") возвращает пустой массив.

Согласно этому результат "".split(",") должен быть пустым массивом из-за второго шага, верно?

Должен. К сожалению, это искусственно введенный угловой случай. И это плохо, но по крайней мере это задокументировано в java.util.regex.Pattern, если вы не забываете взглянуть на документацию:

Для n == 0 результат такой же, как для n <0, за исключением завершающих пустых строк не будут возвращены. <strong>(Обратите внимание, что случай, когда вход сам по себе пустая строка является специальной, как описано выше, и параметр limit там не распространяется.)

Решение 1: всегда передавать -1 в качестве второго параметра

Итак, я советую вам всегда передавать n == -1 в качестве второго параметра (это пропустит второй шаг выше), если вы не знаете, чего конкретно хотите достичь / вы уверены, что пустая строка - это не то, что ваша программа получит в качестве входа.

Решение 2. Использование класса Splitter Guava

Если вы уже используете Guava в своем проекте, вы можете попробовать класс Splitter (документация) . Он имеет очень богатый API и делает ваш код очень простым для понимания.

Splitter.on(".").split(".a.b.c.") // "", "a", "b", "c", ""
Splitter.on(",").omitEmptyStrings().split("a,,b,,c") // "a", "b", "c"
Splitter.on(CharMatcher.anyOf(",.")).split("a,b.c") // "a", "b", "c"
Splitter.onPattern("=>?").split("a=b=>c") // "a", "b", "c"
Splitter.on(",").limit(2).split("a,b,c") // "a", "b,c"
31 голосов
/ 11 февраля 2011

По той же причине, что

",test" split ','

и

",test," split ','

вернет массив размера 2. Все до первого совпадения будет возвращено в качестве первого элемента.

22 голосов
/ 15 апреля 2013

"a".split(",") -> "a" следовательно "".split(",") -> ""

4 голосов
/ 11 февраля 2011

На всех языках программирования я знаю, что пустая строка все еще является допустимой строкой. Таким образом, выполнение разбиения с использованием любого разделителя всегда будет возвращать массив одного элемента, где этот элемент является пустой строкой. Если бы это была пустая (не пустая) строка, это была бы другая проблема.

2 голосов
/ 20 октября 2017

Это split поведение унаследовано от Java, к лучшему или к худшему ...
Scala не переопределяет определение из примитива String.

Обратите внимание, что вы можете использовать аргумент limit для изменения поведения :

Параметр limit определяет количество применений шаблона и, следовательно, влияет на длину результирующего массива. Если предел n больше нуля, то шаблон будет применен не более n - 1 раз, длина массива будет не больше n, а последняя запись массива будет содержать все входные данные за пределами последнего сопоставленного разделителя. Если n не является положительным, то шаблон будет применяться столько раз, сколько возможно, и массив может иметь любую длину. Если n равно нулю, шаблон будет применяться столько раз, сколько возможно, массив может иметь любую длину, а завершающие пустые строки будут отбрасываться.

т.е. Вы можете установить limit=-1, чтобы получить поведение (всех?) других языков:

@ ",a,,b,,".split(",")
res1: Array[String] = Array("", "a", "", "b")

@ ",a,,b,,".split(",", -1)  // limit=-1
res2: Array[String] = Array("", "a", "", "b", "", "")

Кажется, хорошо известно, что поведение Java весьма запутанно , но:

Поведение выше можно наблюдать как минимум с Java 5 до Java 8.

Была попытка изменить поведение для возврата пустого массива при разбиении пустой строки в JDK-6559590 . Однако вскоре он был возвращен в JDK-8028321 , когда он вызывает регрессию в различных местах. Это изменение никогда не войдет в первоначальный выпуск Java 8.

Примечание: Метод split не был в Java с самого начала (он не в 1.0.2 ), но на самом деле он существует как минимум с 1.4 (например, см. JSR51 * 1040). * около 2002 г.) Я все еще расследую ...

Что непонятно, так это то, почему Java выбрала это в первую очередь (я подозреваю, что это изначально было оплошностью / ошибкой в ​​«крайнем случае»), но теперь безвозвратно запекается в язык и поэтому остается .

0 голосов
/ 04 октября 2018

Пустая строка не имеет специального статуса при разбиении строки. Вы можете использовать:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...