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 марта, 10:27
Nice
Dmitry
Уровень 26
16 сентября 2023, 12:36
а можно как нибудь разделить строку на отдельные буквы?
ElenaN
Уровень 37
10 октября 2023, 02:59
String str="hello";
           for(int i=0; i<str.length(); i++){
               char ch=str.charAt(i);
               System.out.print(ch);
           }
Denis Odesskiy Full Stack Developer
11 ноября 2023, 21:24
String product = "Orange";
// Можно разделить так:
String[] str = product.split("");
// И вывести в консоль так
for(String ch: str) {
    System.out.println(ch);
}
// Ну или так
System.out.println(Arrays.toString(str));
Hokkaido Android Developer в Netflix
11 января, 18:54
String[] arr = {"Hello"};
char[] charArray = arr[0].toCharArray();
System.out.println(Arrays.toString(charArray)); // output: [H, e, l, l, o]
Alexander Minaev
Уровень 27
25 марта 2023, 19:48
если не хотите экранировать или не знаете, надо ли, просто пишите text.split(Pattern.quote("<нужный знак>")); Тогда значение всегда будет строковым и не касаться регулярок. Ну и если нет автоимпорта, то не забудьте импортировать java.util.regex.Pattern
MmN
Уровень 23
13 ноября 2022, 12:48
Статья класс, можно добавить, что в качестве параметра split принимает и сразу несколько разделителей
String str = "Амо/ре.амо,ре";
String[] words = str.split("[/\\.,]");    // Амо  ре  амо  ре
Anonymous #3127985 Отец господ в Tinkoff.ru
19 ноября 2022, 11:23
В этом и есть суть регулярных выражений
Ivan Ivanov
Уровень 1
13 сентября 2022, 06:36
А если нет разделителей, но есть сплошная строка длиной N символов, и нужно разделить ее, допустим, на число M ? То как в этом случае быть?
Svyat
Уровень 38
27 сентября 2022, 10:29
char[] arr = str.toCharArray(); // Преобразуем строку str в массив символов (char) split так к сожалению не может)
Mick Thomson
Уровень 15
28 февраля 2023, 22:39
Так она разделится на N символов в таком случае, а не на M, разве нет?
Dregid Backend Developer в Сбербанк
12 сентября 2022, 14:08
Когда я в первый раз прочитал данную статью, ничего не понял и посчитал данную статью бесполезной. А на тот момент я изучал первый месяц. И сейчас, спустя еще 2 месяца я наконец то понял что тут написано) И могу теперь смело сказать что да, статья полезная.
CrazyKISS
Уровень 19
6 августа 2022, 18:42
split("\\|"); почему экранируем 2мя слешами? почему не одним, как обычно?
Anonymous #3068853
Уровень 3
7 августа 2022, 15:26
Обратный слэш является специальным символом и в регулярных выражениях, и в строках Java. В регулярном выражеении в этом месте должен быть слэш. Но чтобы его туда поставить, в строковом литерале приходится написать его дважды. Например:
System.out.println("\\".length()); //вывод: 1
bighugеmistеr Android Developer
29 мая 2022, 05:09
Не показали только случай, когда "разделители" идут подряд.
YesOn
Уровень 13
10 мая 2022, 03:09
Очень полезная и информативная статья, спасибо!
9 февраля 2022, 21:41
А если в задаче разделитель вводится с клавиатуры, то как добавить\\ чтоб ошибки зарезервированного знака не было?