Давай поговорим о методе String split: что он делает и зачем нужен. Несложно догадаться, что он делит строку, но как это работает на практике? Давай подробно рассмотрим работу метода и обсудим некоторые неочевидные детали, а заодно узнаем, сколько методов split есть в классе String на самом деле. Погнали!
Обрати внимание на различия между последними двумя строками в таблице выше.
В предпоследней строке разделителем выступает символ запятой, поэтому строка разбилась таким образом, что в некоторых словах есть ведущие пробелы.
В последней же строке в качестве разделителя мы использовали символ запятой и символ пробела. Поэтому в результирующем массиве не оказалось строк с ведущими пробелами.
Это просто маленькая деталь, в которой демонстрируется, как важно внимательно подбирать правильный разделитель.
Определение и сигнатура для Java String.split
Метод split в Java разделяет строку на подстроки, используя разделитель, который определяется с помощью регулярного выражения. Приведем сигнатуру метода и начнем наше погружение:
String[] split(String regex)
Из сигнатуры ясны две вещи:- Метод возвращает массив строк.
- Метод принимает строку regex в качестве параметра.
- Метод возвращает массив строк.
В определении есть такие слова: "Метод split в Java разделяет строку на подстроки". Данные подстроки собираются методом в массив и представляют собой его возвращаемое значение.
- Метод принимает строку regex в качестве параметра.
Опять же, вспомним определение: "разделяет строку на подстроки, используя разделитель, который определяется с помощью регулярного выражения". Принимаемый параметр regex — это шаблон регулярного выражения, который применяется к исходной строке и по совпадениям определяет в ней символ (или комбинацию символов) разделителя.
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. Он нужен для разделения строки на составные части с помощью специального разделителя. Метод возвращает массив строк (составные части строки). Принимает в себя регулярное выражение, по которому находит символ(ы) разделителя. Мы рассмотрели различные тонкости работы данного метода:- ведущий символ разделителя;
- перегруженный собрат с двумя аргументами.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ