JavaRush /Java блог /Random /Метод split в Java: делим строку на части
Автор
Александр Выпирайленко
Java-разработчик в Toshiba Global Commerce Solutions

Метод split в Java: делим строку на части

Статья из группы Random
Давай поговорим о методе String split: что он делает и зачем нужен. Несложно догадаться, что он делит строку, но как это работает на практике? Давай подробно рассмотрим работу метода и обсудим некоторые неочевидные детали, а заодно узнаем, сколько методов split есть в классе String на самом деле. Погнали!

Определение и сигнатура для Java String.split

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

String[] split(String regex)
Из сигнатуры ясны две вещи:
  1. Метод возвращает массив строк.
  2. Метод принимает строку regex в качестве параметра.
Разберем каждую вещь по отдельности в разрезе определения, приведенного выше.
  1. Метод возвращает массив строк.

    В определении есть такие слова: "Метод split в Java разделяет строку на подстроки". Данные подстроки собираются методом в массив и представляют собой его возвращаемое значение.

  2. Метод принимает строку regex в качестве параметра.

    Опять же, вспомним определение: "разделяет строку на подстроки, используя разделитель, который определяется с помощью регулярного выражения". Принимаемый параметр regex — это шаблон регулярного выражения, который применяется к исходной строке и по совпадениям определяет в ней символ (или комбинацию символов) разделителя.

Метод split в Java: делим строку на части - 1

Split на практике

Теперь ближе к делу. Представим, что у нас есть строка со словами. Например, такая:
I love Java
Нам нужно разбить строку на слова. Мы видим, что в данной строке слова разделены друг от друга пробелами. Пробел — идеальный кандидат на роль разделителя в данном случае. Так выглядит код решения данной задачи:

public class Main {
    public static void main(String[] args) {
        String str = "I love Java";
        String[] words = str.split(" ");
        for (String word : words) {
            System.out.println(word);
        }
    }
}
Выводом метода main будут следующие строки:
I love Java
Посмотрим еще на несколько примеров того, как бы отработал метод split:
Строка Разделитель Результат работы метода
"I love Java" " " (символ пробела) {"I", "love", "Java"}
"192.168.0.1:8080" ":" {"192.168.0.1", "8080"}
"Красный, оранжевый, желтый" "," {"Красный", " оранжевый", " желтый"}
"Красный, оранжевый, желтый" ", " {"Красный", "оранжевый", "желтый"}
Обрати внимание на различия между последними двумя строками в таблице выше. В предпоследней строке разделителем выступает символ запятой, поэтому строка разбилась таким образом, что в некоторых словах есть ведущие пробелы. В последней же строке в качестве разделителя мы использовали символ запятой и символ пробела. Поэтому в результирующем массиве не оказалось строк с ведущими пробелами. Это просто маленькая деталь, в которой демонстрируется, как важно внимательно подбирать правильный разделитель.

Ведущий разделитель

Есть еще один важный нюанс. Если исходная строка начинается с разделителя, первым элементом результирующего массива будет пустая строка. На примере это будет выглядеть так: Исходная строка: " I love Java" Разделитель: " " Результирующий массив: { "", "I", "love", "Java" } Но если исходная строка заканчивается разделителем, а не начинается, результат будет иным: Исходная строка: "I love Java " Разделитель: " " Результирующий массив: { "I", "love", "Java" } Смотрим в коде на вариации работы метода split с символом разделителя в конце и/или начале исходной строки:

public class Main {
    public static void main(String[] args) {
        print("I love Java".split(" "));
        print(" I love Java".split(" "));
        print("I love Java ".split(" "));
        print(" I love Java ".split(" "));
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}
Вывод метода main будет таким:
[I, love, Java] [, I, love, Java] [I, love, Java] [, I, love, Java]
Еще раз обрати внимание: когда в исходной строке первый символ — это символ разделителя, в результате в массиве первым элементом будет пустая строка.

Перегруженный собрат

В классе String есть еще один метод split с такой сигнатурой:

String[] split(String regex, int limit)
У этого метода есть дополнительный параметр limit: он определяет, какое количество раз шаблон regex будет применяться к исходной строке. Ниже — пояснения:

limit > 0

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

public class Main {
    public static void main(String[] args) {
        print("I love Java".split(" ", 1));
        print("I love Java".split(" ", 2));
        /*
         Вывод: 
         [I love Java]
         [I, love Java]
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}

limit < 0

Шаблон для поиска разделителя применяется к строке столько раз, сколько это возможно. Длина итогового массива может быть любой. Пример:

public class Main {
    public static void main(String[] args) {
        // Обратите внимание на пробел в конце строки
        print("I love Java ".split(" ", -1));
        print("I love Java ".split(" ", -2));
        print("I love Java ".split(" ", -12));
        /*
         Вывод:
        [I, love, Java, ]
        [I, love, Java, ]
        [I, love, Java, ]
        
        Обратите внимание: последний элемент массива —
        пустая строка, возникшая из-за пробела
        в конце исходной строки. 
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}

limit 0

Как и в случае с limit < 0, шаблон для поиска разделителя применяется к строке столько раз, сколько это возможно. Итоговый массив может быть любой длины. Если последние элементы равны пустой строке, в итоговом массиве они будут отброшены. Пример:

public class Main {
    public static void main(String[] args) {
        // Обратите внимание на пробел в конце строки
        print("I love Java ".split(" ", 0));
        print("I love Java ".split(" ", 0));
        print("I love Java ".split(" ", 0));
        /*
         Вывод:
        [I, love, Java]
        [I, love, Java]
        [I, love, Java]
        Обратите внимание на отсутствие пустых строк в конце                       массивов
        */
    }

    static void print(String[] arr) {
        System.out.println(Arrays.toString(arr));
    }
}
Если мы посмотрим на реализацию метода split с одним аргументом, увидим, что данный метод вызывает своего перегруженного собрата со вторым аргументом, равным нулю:

    public String[] split(String regex) {
        return split(regex, 0);
    }

Различные примеры

В рабочей практике иногда бывает так, что у нас есть строка, составленная по определенным правилам. Данная строка может "приходить" в нашу программу откуда угодно:
  • из стороннего сервиса;
  • из запроса к нашему серверу;
  • из конфигурационного файла;
  • и т.д.
Обычно в такой ситуации программисту известны "правила игры". Скажем, программист знает, что у него есть информация о пользователе, которая хранится по такому шаблону:
user_id|user_login|user_email
Для примера возьмем конкретные значения:
135|bender|bender@gmail.com
И вот перед программистом стоит задача: написать метод, который отправляет электронное письмо пользователю. В его распоряжении — информация о юзере, записанная в указанном выше формате. Ну а подзадача, которую мы продолжим разбирать — вычленить email-адрес из общей информации о пользователе. Это один из примеров, когда метод split может оказаться полезным. Ведь если мы взглянем на шаблон, мы поймем: чтобы вычленить email-адрес пользователя из всей информации, нам нужно всего лишь разделить строку с помощью метода split. Тогда email-адрес будет лежать в последнем элементе результирующего массива. Приведем пример такого метода, который принимает в себя строку, содержащую информацию о пользователе, и возвращает email пользователя. Для упрощения предположим, что данная строка всегда соответствует нужному нам формату:

public class Main {
    public static void main(String[] args) {
        String userInfo = "135|bender|bender@gmail.com";
        System.out.println(getUserEmail(userInfo));
        // Вывод: bender@gmail.com
    }

    static String getUserEmail(String userInfo) {
        String[] data = userInfo.split("\\|");
        return data[2]; // или data[data.length - 1]
    }
}
Обратите внимание на разделитель: "\\|". Так как в регулярных выражениях “|” — это специальный символ, на котором завязана определенная логика, чтобы использовать его как обычный (тот, который мы хотим найти в исходной строке), нужно экранировать этот символ с помощью двух обратных слешей. Рассмотрим другой пример. Допустим, у нас есть информация о заказе, которая записана примерно в таком формате:
item_number_1,item_name_1,item_price_1;item_number_2,item_name_2,item_price_2;...;item_number_n,item_name_n,item_price_n
Ну или же возьмем конкретные значения:
1,огурцы,20.05;2,помидоры,123.45;3,зайцы,0.50
Перед нами стоит задача: рассчитать итоговую стоимость заказа. Здесь нам придется применять метод split несколько раз. Первым шагом мы разделим строку через символ ";", на составные части. Тогда в каждой такой части у нас будет информация об отдельном товаре, которую мы сможем обработать в дальнейшем. А затем, в рамках каждого товара будем разделять информацию с помощью символа "," и брать из результирующего массива элемент с определенным индексом (в котором хранится цена), приводить ее к числовому виду и составлять итоговую стоимость заказа. Напишем метод, который все это посчитает:

public class Main {
    public static void main(String[] args) {
        String orderInfo = "1,огурцы,20.05;2,помидоры,123.45;3,зайцы,0.50";
        System.out.println(getTotalOrderAmount(orderInfo));
        // Вывод: 144.0
    }

    static double getTotalOrderAmount(String orderInfo) {
        double totalAmount = 0d;
        final String[] items = orderInfo.split(";");

        for (String item : items) {
            final String[] itemInfo = item.split(",");
            totalAmount += Double.parseDouble(itemInfo[2]);
        }

        return totalAmount;
    }
}
Попробуй самостоятельно разобраться с тем, как работает данный метод. На основе данных примеров можно сказать, что метод split используется тогда, когда у нас есть некоторая информация в строковом виде, из которой нам необходимо вычленить какую-то более специфическую информацию.

Итоги

Мы рассмотрели с тобой метод split класса String. Он нужен для разделения строки на составные части с помощью специального разделителя. Метод возвращает массив строк (составные части строки). Принимает в себя регулярное выражение, по которому находит символ(ы) разделителя. Мы рассмотрели различные тонкости работы данного метода:
  • ведущий символ разделителя;
  • перегруженный собрат с двумя аргументами.
Также попробовали смоделировать некоторые ситуации “из жизни”, в которых использовали метод split для решения пусть и вымышленных, но вполне реалистичных проблем.
Комментарии (24)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Ислам Уровень 33
23 марта 2024
Nice
Dmitry Уровень 26
16 сентября 2023
а можно как нибудь разделить строку на отдельные буквы?
Alexander Minaev Уровень 27
25 марта 2023
если не хотите экранировать или не знаете, надо ли, просто пишите text.split(Pattern.quote("<нужный знак>")); Тогда значение всегда будет строковым и не касаться регулярок. Ну и если нет автоимпорта, то не забудьте импортировать java.util.regex.Pattern
MmN Уровень 23
13 ноября 2022
Статья класс, можно добавить, что в качестве параметра split принимает и сразу несколько разделителей

String str = "Амо/ре.амо,ре";
String[] words = str.split("[/\\.,]");    // Амо  ре  амо  ре
Ivan Ivanov Уровень 1
13 сентября 2022
А если нет разделителей, но есть сплошная строка длиной N символов, и нужно разделить ее, допустим, на число M ? То как в этом случае быть?
Dregid Уровень 40
12 сентября 2022
Когда я в первый раз прочитал данную статью, ничего не понял и посчитал данную статью бесполезной. А на тот момент я изучал первый месяц. И сейчас, спустя еще 2 месяца я наконец то понял что тут написано) И могу теперь смело сказать что да, статья полезная.
CrazyKISS Уровень 19
6 августа 2022
split("\\|"); почему экранируем 2мя слешами? почему не одним, как обычно?
bighugеmistеr Уровень 15
29 мая 2022
Не показали только случай, когда "разделители" идут подряд.
YesOn Уровень 13
10 мая 2022
Очень полезная и информативная статья, спасибо!
9 февраля 2022
А если в задаче разделитель вводится с клавиатуры, то как добавить\\ чтоб ошибки зарезервированного знака не было?