Разделение строки Java удалено пустым значением

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

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

Я ожидаю получить 8 значений. [5,6,7, EMPTY, 8,9, EMPTY, УДАЛИТЬ] Но я получаю только 6 значений.

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

Ответ 1

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

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

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

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

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

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

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

Exception

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

Ответ 2

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

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

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

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

Doc:

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

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

Ответ 3

От Домен API:

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

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

Ответ 4

Другой вариант - использовать разветкитель Guava. У него нет накладных расходов на регулярное выражение (которое вам не нужно в этом случае) и по умолчанию не отбрасывает пустые строки.

Например:

 String data = "5|6|7||8|9||";
 Iterable<String> results = Splitter.on('|').split(data);
 // convert to array
 String[] asArray = Iterables.toArray(results, String.class);

Для получения дополнительной информации см. wiki: https://github.com/google/guava/wiki/StringsExplained

Ответ 5

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.

Ответ 6

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

 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]+");

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