Как разделить строку?

Есть строка построенная по правилам. "Город [синоним1, .., синонимN] {ссылка}, Город2 [] {}]" текста в квадратных и\или фигурных скобках может не быть. Пример

    String input = "Москва [Мск, Белокаменная] {msk.com}, Санкт-Петербург [Спб, Питер], Ростов, Калининград [Кёниг] {123.com}";

Нужно регулярное выражение, чтобы поделить на части

  1. Москва [Мск, Белокаменная] {msk.com}
  2. Санкт-Петербург [Спб, Питер]
  3. Ростов
  4. Калининград [Кёниг] {123.com}

И затем нужно каждую строку разделить на Город,синонимы и ссылки

  1. Москва
  2. [Мск, Белокаменная]
  3. {msk.com}

как я понял тут надо вводить условия для предшествующего текста вида "?<=\\{*\\})||(?<=[*]), ?" Подскажите, как составить?


Ответы (2 шт):

Автор решения: Wiktor Stribiżew

Вы можете использовать

"(?U)(\\w+(?:-\\w+)*)(?:\\s*(?:\\[([^\\]\\[]*)]))?(?:,?\\s*\\{([^{}]*)\\})?"

См. пример работы выражения. Подробности:

  • (?U) - Pattern.UNICODE_CHARACTER_CLASS - включает поддержку Юникода \w
  • (\w+(?:-\w+)*) - Подмаска №1: один и более буквоцифровых символов, за которыми могут следовать 0 и более повторов символа - и один и более буквоцифровых символов
  • (?:\s*\[([^\]\[]*)])? - опциональная последовательность 0 и более пробельных символов, затем [, 0 и более символов, отличных от ] и [ (Подмаска №2), а затем ]
  • (?:,?\s*\{([^{}]*)\})? - опциональная последовательность необязательной запятой, 0 и более пробельных символов, затем {, 0 и более символов, отличных от } и { (Подмаска №3), а затем }.

Код на Java:

String input = "Москва [Мск, Белокаменная] {msk.com}, Санкт-Петербург [Спб, Питер], Ростов, Калининград [Кёниг] {123.com}\nРостов {123.com}";
Pattern pattern = Pattern.compile("(?U)(\\w+(?:-\\w+)*)(?:\\s*(?:\\[([^\\]\\[]*)]))?(?:,?\\s*\\{([^{}]*)\\})?");
Matcher matcher = pattern.matcher(input);
while (matcher.find()){
    System.out.println("-------------\nСовпадение: " + matcher.group());
    System.out.println("Подмаска №1: " + matcher.group(1));
    if (matcher.group(2) != null) {
        System.out.println("Подмаска №2: " + matcher.group(2)); 
    }
    if (matcher.group(3) != null) {
        System.out.println("Подмаска №3: " + matcher.group(3)); 
    }
} 

Результат:

-------------
Совпадение: Москва [Мск, Белокаменная] {msk.com}
Подмаска №1: Москва
Подмаска №2: Мск, Белокаменная
Подмаска №3: msk.com
-------------
Совпадение: Санкт-Петербург [Спб, Питер]
Подмаска №1: Санкт-Петербург
Подмаска №2: Спб, Питер
-------------
Совпадение: Ростов
Подмаска №1: Ростов
-------------
Совпадение: Калининград [Кёниг] {123.com}
Подмаска №1: Калининград
Подмаска №2: Кёниг
Подмаска №3: 123.com
-------------
Совпадение: Ростов {123.com}
Подмаска №1: Ростов
Подмаска №3: 123.com
→ Ссылка
Автор решения: roddar92

Для второй части задачи здесь подойдёт функция .split(" "), когда разбиваешь каждую часть по пробелу.

Для первой задачи будет мало разбить текст по запятой, потому что запятая может быть как и разделителем частей, так и находиться в блоке перечисления между { } и [ ]. Решение для первой части может выглядеть следующим образом:

StringBuilder sb = new StringBuilder();
List<String> parts = new ArrayList<>();
int bracketsCounter = 0;
for (int i = 0; i < input.length(); i++) {
    String symbol = String.valueOf(input.charAt(i));
    if ("({[".contains(symbol)) bracketsCounter++;
    else if (")}]".contains(symbol)) bracketsCounter--;

    if (symbol.equals(",") && bracketsCounter == 0) {
        if (sb.length() > 0) {
            parts.add(sb.toString());
            sb = new StringBuilder();
        }
    } else {
        sb.append(symbol);
    }
}

if (sb.length() > 0) {
    parts.add(sb.toString());
}
→ Ссылка