«Помогите, я не могу разделить строку!» — история одной проблемы
Представьте: вы пишете на Java парсер логов, обрабатываете CSV-файл или просто хотите разбить пользовательский ввод на слова. И тут — стоп. Как это сделать? Если вы когда-нибудь гуглили «How do I split a string in Java», то знаете: этот вопрос на Stack Overflow собрал сотни тысяч просмотров. Не потому, что Java-программисты ленивые, а потому что split() — штука мощная, но с подводными камнями.
В этой статье мы разберем разделение строк в Java от А до Я. Вы узнаете, как работает метод split(), какие сюрпризы готовят регулярные выражения, и как не наступить на грабли, которые ждут каждого второго новичка. Погнали!
Метод split(): ваш главный инструмент
Класс String в Java предлагает два перегруженных варианта метода split():
public String[] split(String regex)
public String[] split(String regex, int limit)
Первый вариант принимает регулярное выражение и возвращает массив строк. Второй — то же самое, но с ограничением на количество частей. Звучит просто? Давайте посмотрим на примеры.
Базовый пример: разделение по пробелу
public class SplitExample {
public static void main(String[] args) {
String text = "Java разделяет строки легко";
String[] words = text.split(" ");
for (String word : words) {
System.out.println(word);
}
}
}
Вывод:
Java
разделяет
строки
легко
Работает? Работает. Но что, если у вас несколько пробелов подряд? Тогда в массив попадут пустые строки. Неприятно, правда?
Разделение строки в Java по запятой (CSV)
Одна из самых частых задач — разделить строку в Java по запятой. Допустим, у вас есть CSV-строка:
String csv = "яблоко,груша,банан,апельсин";
String[] fruits = csv.split(",");
for (String fruit : fruits) {
System.out.println(fruit.trim()); // trim() убирает лишние пробелы
}
Вывод:
яблоко
груша
банан
апельсин
Обратите внимание: мы добавили trim(), потому что в реальных данных после запятой часто идут пробелы. Без этого вы получите " яблоко" с лидирующим пробелом — и потом будете гадать, почему строки не совпадают.
Регулярные выражения: магия и боль
Метод split() принимает регулярное выражение. Это даёт огромную гибкость, но требует аккуратности. Рассмотрим популярные сценарии.
Разделение по точке
Хотите разбить IP-адрес "192.168.1.1"? Наивный код str.split(".") не сработает. Почему? Потому что точка в регулярных выражениях — это спецсимвол, означающий «любой символ». В результате вы получите массив пустых строк.
Правильное решение — экранировать точку:
String ip = "192.168.1.1";
String[] parts = ip.split("\\."); // Двойной бэкслеш!
for (String part : parts) {
System.out.println(part);
}
// Вывод: 192 168 1 1
Запомните: в Java для экранирования в регулярках используется двойной бэкслеш \\. Одиночный \ — это управляющий символ для строки, а двойной — уже для regex.
Разделение по нескольким разделителям
Что делать, если строка содержит и запятые, и точки с запятой, и пробелы? Используйте символьный класс в квадратных скобках:
String messy = "яблоко;груша,банан апельсин";
String[] items = messy.split("[;,\\s]+"); // ; или , или пробельные символы
for (String item : items) {
System.out.println(item);
}
// Вывод: яблоко груша банан апельсин
Знак + означает «один или более» — это гарантирует, что последовательность разделителей не создаст пустых строк.
Параметр limit: контроль над результатом
Второй вариант split() с параметром limit — штука недооценённая. Он управляет тем, сколько раз применяется разделение:
- limit > 0 — шаблон применяется limit-1 раз, остаток строки идёт как последний элемент.
- limit = 0 — шаблон применяется сколько нужно, пустые строки в конце удаляются.
- limit < 0 — шаблон применяется сколько нужно, пустые строки сохраняются.
Пример:
String data = "a,b,c,d,e";
// limit = 3: разделим только два раза, остальное — целиком
String[] parts1 = data.split(",", 3);
System.out.println(Arrays.toString(parts1));
// [a, b, c,d,e]
// limit = 0 (по умолчанию): полное разделение, пустые в конце удаляются
String[] parts2 = data.split(",", 0);
System.out.println(Arrays.toString(parts2));
// [a, b, c, d, e]
// limit = -1: полное разделение, пустые сохраняются
String data2 = "a,,c,";
String[] parts3 = data2.split(",", -1);
System.out.println(Arrays.toString(parts3));
// [a, , c, ] — обратите внимание на пустые строки!
Это критично, когда вы работаете с CSV или логами, где пустые поля имеют значение.
Частые ошибки и как их избежать
Ошибка 1: Забыли экранировать спецсимволы
Кроме точки, экранирования требуют: |, *, +, ?, ^, $, {, }, (, ), [, ], \. Пример с вертикальной чертой:
// Неправильно:
String[] bad = "a|b|c".split("|"); // Разделит по каждому символу!
// Правильно:
String[] good = "a|b|c".split("\\|"); // [a, b, c]
Ошибка 2: Путаница с пробелами
Если вы используете " " как разделитель, а в строке несколько пробелов — получите пустые строки. Решение: split("\\s+") — это разделит по одному или более пробельным символам (включая табуляцию).
Ошибка 3: Забыли про trim()
После разделения по запятым или