Java String.split(delim) оставляет пустую строку в начале, если исходная строка начинается с разделителя

Если вы используете .split(delim) в строке, которая начинается с разделителя, результирующий массив начнется с пустой строки. Вот пример:

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        String[] s = " aaa bbb ccc ".split("[^\\w]+");

        System.out.println(Arrays.toString(s));
    }
}

результат:

[, aaa, bbb, ccc]

Хотя я ожидал, что это будет

[aaa, bbb, ccc]

Всегда читайте Javadoc: «Когда в начале этой строки есть совпадение положительной ширины, в начало результирующего массива включается пустая ведущая подстрока. Однако совпадение с нулевой шириной в начале никогда не создает такую ​​пустую ведущую подстроку». ." Ответ @DCurtis - одно из возможных решений.

Jim Garrison 09.06.2024 02:24

Так работает этот метод, и нет способа заставить его работать так, как я хотел...

Andrey Voeyko 09.06.2024 02:39

Да, это особенность, а не ошибка. По определению между элементами стоит разделитель. Если ваш ввод начинается с разделителя, это означает, что первый элемент отсутствует. Пустой объект String — это подходящий способ в Java представить отсутствующий текст, либо он, либо null.

Basil Bourque 09.06.2024 03:26
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
3
75
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Используйте метод String.trim() перед разделением()

К сожалению, это применимо только в приведенном мной примере. На самом деле, мне тоже нужно что-то вроде ". aaa bbb ccc", чтобы стать [aaa,bbb,ccc].

Andrey Voeyko 09.06.2024 02:21

На самом деле, мне нужно что-то вроде «. aaa bbb ccc», чтобы также стать [aaa,bbb,ccc]. Это просто звучит как неверный ввод/плохой синтаксический анализ. Почему бы и нет [., aaa, bbb, ccc]? Если это действительно так, похоже, вы вообще не хотите String::split

g00se 09.06.2024 10:26
Ответ принят как подходящий

Вы можете использовать (?i)[a-z0-9_]+:

  • (?i) — это нечувствительный флаг, который игнорирует и ослабляет чувствительность к регистру (например, apple, Apple и APPLE обрабатываются одинаково).
  • [a-z0-9_]: разрешен ли список символов, и вы можете его изменить, если хотите. (Примечание: A-Za-z0-9_ и \w одинаковы.)
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Solution {
    public static void main(String[] args) {
        final String regex = "(?i)[a-z0-9_]+";
        final String string = " aaa bbb ccc  \n"
                + "aaa bbb        \n"
                + "       ccc        12aaa _bbb 1_ccc          hhh               ";

        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
        final Matcher matcher = pattern.matcher(string);

        while (matcher.find()) {
            System.out.println("Full match: " + matcher.group(0));

            for (int i = 1; i <= matcher.groupCount(); i++) {
                System.out.println("Group " + i + ": " + matcher.group(i));
            }
        }
    }
}

Принты

Full match: aaa
Full match: bbb
Full match: ccc
Full match: aaa
Full match: bbb
Full match: ccc
Full match: 12aaa
Full match: _bbb
Full match: 1_ccc
Full match: hhh

Вы также можете сохранить матчи в ArrayList():

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.List;

public class Solution {
    public static void main(String[] args) {
        final String regex = "(?i)[a-z0-9_]+";
        final String string = " aaa bbb ccc  \n"
                + "aaa bbb        \n"
                + "       ccc        12aaa _bbb 1_ccc          hhh               ";

        final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
        final Matcher matcher = pattern.matcher(string);

        List<String> matches = new ArrayList<>();

        while (matcher.find()) {
            matches.add(matcher.group(0));
        }

        for (String match : matches) {
            System.out.println(match);
        }
    }
}

Принты

aaa
bbb
ccc
aaa
bbb
ccc
12aaa
_bbb
1_ccc
hhh

Вы также можете использовать split():

import java.util.ArrayList;
import java.util.List;

public class Solution {
    public static void main(String[] args) {
        final String string = " aaa bbb ccc  \n"
                + "aaa bbb        \n"
                + "       ccc        12aaa _bbb 1_ccc          hhh               ";
        final String regex = "\\s+";

        String[] parts = string.split(regex);
        List<String> matches = new ArrayList<>();

        for (String part : parts) {
            if (!part.isEmpty()) {
                matches.add(part);
            }
        }

        for (String match : matches) {
            System.out.println(match);
        }
    }
}

Так что на самом деле правильным ответом было бы использовать Matcher и Pattern для разделения строки вместо метода .split()...

Andrey Voeyko 09.06.2024 02:24

@AndreyVoeyko Это один из способов сделать это. Временная сложность равна O(N). Вы также можете использовать String[] parts = string.split(regex);.

user24714692 09.06.2024 02:25

Если вам интересно, вот потоковое решение. Этот конкретный соответствует всему, что не имеет пробелов.

  • [\\S]+ — класс символов, состоящий из одного или нескольких символов без пробелов.
String str = "     aaa  Foo  bbb    ccc  ab123d _aksks_ ";

String[] result = Pattern.compile("[\\S]+").matcher(str).results()
        .map(MatchResult::group).toArray(String[]::new);

System.out.println(Arrays.toString(result));

принты

[aaa, Foo, bbb, ccc, ab123d, _aksks_]

Вы можете управлять разделителем, изменяя класс символов в регулярном выражении. Итак, если строка разделена сочетанием пробелов и запятых, вы можете использовать [^\\s,]+. В котором говорится, что совпадение соответствует всему, кроме пробелов и запятых.

Другие вопросы по теме