Чому "розділення" на порожній рядок повертає не порожній масив?


111

Розділити на порожній рядок повертає масив розміром 1:

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

Враховуйте, що це повертає порожній масив:

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

Будь ласка, поясніть :)


5
Крім того, це здається невідповідним поведінці, що спостерігається, коли рядок містить лише один екземпляр роздільника. У цьому випадку результатом є фактично порожній масив: ",". Split (","). Length == 0
LD.

Відповіді:


37

З тієї ж причини, що

",test" split ','

і

",test," split ','

поверне масив розміром 2. Усе до першого збігу повертається як перший елемент.


5
Порожня рядок - це рядок, не нічого. (де завгодно, але в Excel)
Рафаель,

5
@Raphael Або в базі даних Oracle
Остін

7
@Raphael, на будь-якій іншій мові програмування "".split("wtf").lengthповертається 0. Тільки в JS це 1.: /
Андрій Михайлов - lolmaus

11
@ DanielC.Sobral Добре, чому ж "," split ","повертає масив 0?
Джоан

5
Чому після повернення останнього матчу все також не повернулося?
Дідьє А.

72

Якщо ви розділите помаранчевий нуль разів, у вас рівно одна деталь - апельсин.


8
Але апельсин не порожній (idk, якщо це означало, що маслянисті речовини), це апельсин. Можливо, розщеплення апельсина, який має бути там, але це не так, тому ви отримуєте назад одне значення: порожній простір xD
Нік Роландо

8
Це глибока розмова.

31
Ця метафора має сенс "orange".split(','), але очевидно не має значення для розбиття порожніх рядків. Якщо я розділив мою відсутність оранжевого нуля разів, у мене все одно немає жодного апельсина; чи ми представляємо це як порожній список не-апельсинів, список точно одного жодного апельсина, список дванадцяти не-апельсинів, чи що? Справа не в тому, до чого ми закінчуємо, а в тому, як ми це представляємо.
Мачу

1
Але якщо ви розділите неіснуючу книгу за її сторінками, ви нічого не отримаєте.
SMUsamaShah

49

Методи розбиття Java та Scala діють у два етапи, як це:

  • Спочатку розділіть рядок на роздільник. Природним наслідком є ​​те, що якщо рядок не містить роздільника, повертається однотонний масив, що містить лише вхідну рядок,
  • По-друге, видаліть усі найправіші порожні рядки. Це причина ",,,".split(",")повертає порожній масив.

Відповідно до цього, результат "".split(",")другого кроку повинен бути порожнім масивом, так?

Це повинно. На жаль, це штучно запроваджений кутовий корпус. І це погано, але , по крайней мере , це документовано в java.util.regex.Pattern, якщо ви пам'ятаєте , щоб поглянути на документацію:

Для n == 0 результат такий, як для n <0, за винятком того, що порожні рядки не будуть повернені. (Зауважте, що випадок, коли вхід сам по собі є порожнім рядком, є спеціальним, як описано вище, і граничний параметр там не застосовується.)

Рішення 1: Завжди передайте -1 як другий параметр

Отже, я раджу завжди переходити n == -1як другий параметр (це буде пропускати другий крок вище), якщо ви конкретно не знаєте, чого хочете досягти / ви впевнені, що порожня рядок - це не те, що ваша програма отримала б як вхід.

Рішення 2: Використовуйте клас Guava Splitter

Якщо ви вже використовуєте 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"

1
+1, це єдина відповідь, яка насправді цитує документацію і вказує, що вона суперечить. Однак я не знайшов виділеної частини коментаря у своєму JavaDoc.
Йогу

Я знайшов це в java.util.regex.Pattern, але, здається, його в основному вже немає. На момент написання документа воно, безумовно, було присутнє в офіційному джерелі OpenJDK як javadoc. android.googlesource.com/platform/libcore/+/… Можливо, ми повинні повідомити про помилку?
Rok Kralj

Було б гарною ідеєю повідомити про помилку - поведінка точно не зміниться, але вона має бути принаймні задокументована.
Йогу

@RokKralj Android не використовував бібліотеку OpenJDK, а натомість базувався на Apache Harmony, тож, можливо, ви шукаєте не в тому місці?
lxgr

1
"".split (",", n)створює масив одного елемента для n в (-1, 0, 1) за допомогою Oracle JDK 8. Було б непогано отримати список лише не порожніх лексем - здогадайтеся, може знадобитися повний регекс (щось подібне "[^,\\s]+[^,]*[^,\\s]*").
simon.watts

40

Розщеплення порожнього рядка повертає порожній рядок як перший елемент. Якщо в цільовому рядку не знайдено роздільника, ви отримаєте масив розміром 1, який містить оригінальну рядок, навіть якщо вона порожня.


2
Неправильно. Сплит видаляє всі найправіші порожні рядки, тому результатом повинен бути порожній масив. Дивіться мою відповідь. ",".split(",")повертає порожній масив.
Rok Kralj

23

"a".split(",")-> "a" отже "".split(",")->""


6
Неправильно. Сплит видаляє всі найправіші порожні рядки, тому результатом повинен бути порожній масив. Дивіться мою відповідь. ",".split(",")повертає порожній масив.
Rok Kralj

5

У всіх мовах програмування я знаю, що порожня рядок все ще є дійсною строкою. Таким чином, розбиття за допомогою будь-якого роздільника завжди буде повертати масив одного елемента, де цей елемент є порожнім рядком. Якщо це був нульовий (не порожній) рядок, то це була б інша проблема.


Я думаю, що це функція бібліотеки, а не частина мови. Наприклад, в google guava ви можете опустити порожні рядки. > Iterable <String> pieces = com.google.common.base.Splitter.on (','). OmitEmptyStrings (). Split ("");
oluies

2

Така splitповедінка успадкована від Java, для кращого чи гіршого ...
Скала не перекриває визначення від 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.

Примітка: Спосіб розділення не був у Java з самого початку (це не в 1.0.2 ), але насправді існує принаймні 1,4 (наприклад, див. JSR51 circa 2002). Я досі розслідую ...

Незрозуміло, чому Java обрала це в першу чергу (я підозрюю, що спочатку це був недогляд / помилка у "крайовому випадку"), але тепер безповоротно заграв у мову і так залишається .


Я не впевнений, що це відповідає на питання - хоча це може бути правдою для наведеного тут прикладу, він не допомагає у випадку порожнього рядка - "".split(",")все одно повертає єдиний масив елементів на зразок [""].
DaveyDaveDave

@DaveyDaveDave така очікувана поведінка будь-якої іншої мови. ",,,," - це химерна / інша поведінка у Scala і невідповідна до випадку "".
Енді Хейден

0

Порожній рядок не має спеціального статусу під час розділення рядка. Ви можете використовувати:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.