Java String split удаляет пустые значения

286

Я пытаюсь разделить значение с помощью разделителя. Но я нахожу удивительные результаты

String data = "5|6|7||8|9||";
String[] split = data.split("\\|");
System.out.println(split.length);

Я ожидаю получить 8 значений. [5,6,7, ПУСТО, 8,9, ПУСТО, ПУСТО] Но я получаю только 6 значений.

Есть идеи и как исправить. Неважно, в каком месте находится пустое значение, оно должно быть в массиве.

Reddy
источник

Ответы:

493

split(delimiter)по умолчанию удаляет завершающие пустые строки из массива результатов. Чтобы отключить этот механизм, нам нужно использовать перегруженную версию split(delimiter, limit)с limitотрицательным значением, например

String[] split = data.split("\\|", -1);

Немного подробнее:
split(regex)внутренне возвращает результат split(regex, 0)и в документации этого метода вы можете найти (выделено мое)

limitПараметр контролирует количество раз применяется шаблон и , следовательно , влияет на длину результирующего массива.

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

Если nэто не положительно, то шаблон будет применяться столько раз, сколько возможно, и массив может иметь любую длину.

Если nесть ноль , то шаблон будет применен столько раз , сколько это возможно, массив может иметь любую длину, и конечные пустые строки будут отброшены .

Исключение :

Стоит отметить, что удаление завершающей пустой строки имеет смысл, только если такая пустая строка создается с помощью механизма разделения . Так "".split(anything)как мы не можем разделить ""дальше, мы получим [""]массив результатов .
Это происходит потому, что разделение здесь не произошло, поэтому ""несмотря на то, что оно пустое, а конечный символ представляет собой исходную строку, а не пустую строку, созданную в процессе разделения.

jlordo
источник
2
Вот это да. это сработало блестяще. но -1 как это все меняет?
Редди
1
Вы даже можете попробовать сdata.split("\\|", 8)
Subhrajyoti Majumder
23
Не используйте, split("\\|", 8)потому что это ограничивает первые восемь токенов! Если ваша строка является переменной, вы должны использовать ее split("\\|", -1)так, чтобы она создавала неограниченное количество токенов и не сбрасывала пустые токены в конце.
ADTC,
2
@Reddy -1 ( или любое отрицательное число на самом деле, не имеет значения, что это за абсолютное значение ) сообщает методу split, чтобы в конце оставались пустые токены. По умолчанию 0, что говорит методу об отказе от пустых токенов в конце массива.
ADTC,
8
Очевидно, многие ожидали, что сохранение конечных пустых строк является функциональностью по умолчанию для split(regex). Они оказались здесь и узнали, что это не так.
Аттила
32

Из документации String.split(String regex):

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

Таким образом, вам придется использовать версию String.split(String regex, int limit)с двумя аргументами с отрицательным значением:

String[] split = data.split("\\|",-1);

Doc:

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

Это не пропустит ни одного пустого элемента, включая завершающие.

ppeterka
источник
4

Из String.split () API Doc :

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

Перегруженный String.split (regex, int) больше подходит для вашего случая.

PermGenError
источник
1
Это объясняет поведение, но не отвечает на вопрос.
assylias
@assylias добавил его в мой ответ сейчас :)
PermGenError
4

String[] split = data.split("\\|",-1);

Это не фактическое требование во все времена. Недостаток выше показан ниже:

Scenerio 1:
When all data are present:
    String data = "5|6|7||8|9|10|";
    String[] split = data.split("\\|");
    String[] splt = data.split("\\|",-1);
    System.out.println(split.length); //output: 7
    System.out.println(splt.length); //output: 8

Когда данные отсутствуют:

Scenerio 2: Data Missing
    String data = "5|6|7||8|||";
    String[] split = data.split("\\|");
    String[] splt = data.split("\\|",-1);
    System.out.println(split.length); //output: 5
    System.out.println(splt.length); //output: 8

Реальное требование - длина должна быть 7, хотя данные отсутствуют. Потому что есть случаи, например, когда мне нужно вставить в базу данных или что-то еще. Мы можем достичь этого, используя подход ниже.

    String data = "5|6|7||8|||";
    String[] split = data.split("\\|");
    String[] splt = data.replaceAll("\\|$","").split("\\|",-1);
    System.out.println(split.length); //output: 5
    System.out.println(splt.length); //output:7

То, что я сделал здесь, я удаляю "|" труба в конце, а затем разделить строку. Если у вас есть "," в качестве разделителя, то вам нужно добавить ", $" внутри replaceAll.

Яниш Прадхананга
источник
1

у вас может быть несколько разделителей, включая пробельные символы, запятые, точки с запятой и т. д., используйте разделители в повторяемой группе с [] +, например

 String[] tokens = "a , b,  ,c; ;d,      ".split( "[,; \t\n\r]+" );

у вас будет 4 жетона - a, b, c, d

ведущие разделители в исходной строке должны быть удалены перед применением этого разделения.

в качестве ответа на заданный вопрос:

String data = "5|6|7||8|9||";
String[] split = data.split("[\\| \t\n\r]+");

пробелы добавляются на всякий случай, если вы будете использовать их как разделители вместе с |

Дмитрий Пичугин
источник