Как использовать группу захвата в качестве начала выражения в регулярных выражениях? - PullRequest
0 голосов
/ 04 мая 2018

Задача под рукой: я пытаюсь подготовить к печати определенный список автоматически сгенерированных идентификаторов. Они имеют формат aa-bb-cc-dd-ee-ff-gg ... каждый кортеж можно выбрать с помощью [a-zA-Z0-9] + (неопределенной длины), разделителями являются [-] (max один).

В каждом идентификаторе может быть от одного до девяти кортежей. Если идентификатор 3 кортежа или меньше, я бы вернул одну группу. Если идентификатор больше 3 кортежей (4+), я бы вернул две группы, первая из которых состоит из 3 кортежей, а вторая из остальных.

Одновременно обрабатывается только одна строка. Вот набор тестов:

 one1
 one1-two2
 one1-two2-three3
 one1-two2-three3-4a
 one1-two2-three3-4a-5a
 one1-two2-three3-4a-5a-6a
 one1-two2-three3-4a-5a-6a-7a

Конкретно это будет означать:

 one1 -> {"one1"}
 one1-two2 -> {"one1-two2"}
 one1-two2-three3 -> {"one1-two2-three3"}
 one1-two2-three3-4a -> {"one1-two2-three3", "4a"}
 one1-two2-three3-4a-5a -> {"one1-two2-three3", "4a-5a"}
 one1-two2-three3-4a-5a-6a -> {"one1-two2-three3", "4a-5a-6a"}
 one1-two2-three3-4a-5a-6a-7a -> {"one1-two2-three3", "4a-5a-6a-7a"}

Работа, проделанная до сих пор (это всегда правильно выбирает первую группу)

(^[a-zA-Z0-9]+$)|(^[a-zA-Z0-9]+[-][a-zA-Z0-9]+$)|(^[a-zA-Z0-9]+[-][a-zA-Z0-9]+[-][a-zA-Z0-9]+$)|(^[a-zA-Z0-9]+[-][a-zA-Z0-9]+[-][a-zA-Z0-9]+)

Чего я пытаюсь достичь: начать с конца группы захвата, проверить, не является ли это концом строки, начать читать после первого символа '-', следующего за этой точкой, сопоставить до конца строки ,

Дополнительная информация: я использую встроенный в Java движок регулярных выражений.

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Следующее регулярное выражение будет соответствовать только действительным строкам и возвращает 2 группы захвата:

([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+){0,2})(?:-([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)*))?

Объяснение

(                            Start capture of group 1:
  [a-zA-Z0-9]+                 Match first tuple of group 1
  (?:-[a-zA-Z0-9]+){0,2}       Match 0-2 delimiter+tuple pairs for a total of 1-3 tuples
)                            End capture of group 1
(?:                          Optional:
  -                            Match delimiter initiating group 2
  (                            Start capture of group 2:
    [a-zA-Z0-9]+                 Match first tuple of group 2
    (?:-[a-zA-Z0-9]+)*           Match 0+ delimiter+tuple pairs for a total of 1+ tuples
  )                            End capture of group 2
)?                           End optional

Демо

public static void main(String... args) {
    test("one1",
         "one1-two2",
         "one1-two2-three3",
         "one1-two2-three3-4a",
         "one1-two2-three3-4a-5a",
         "one1-two2-three3-4a-5a-6a",
         "one1-two2-three3-4a-5a-6a-7a",
         "one1-two2-three3-4a-5a-6a-7a-8a",
         "one1_two2"); // fail: invalid character
}

private static void test(String... values) {
    Pattern p = Pattern.compile("([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+){0,2})(?:-([a-zA-Z0-9]+(?:-[a-zA-Z0-9]+){0,3}))?");
    for (String value : values) {
        Matcher m = p.matcher(value);
        if (! m.matches())
            System.out.printf("%s -> NO MATCH%n", value);
        else if (m.start(2) == -1) // capture group 2 not found
            System.out.printf("%s -> {\"%s\"}%n", value, m.group(1));
        else
            System.out.printf("%s -> {\"%s\", \"%s\"}%n", value, m.group(1), m.group(2));
    }
}

выход

one1 -> {"one1"}
one1-two2 -> {"one1-two2"}
one1-two2-three3 -> {"one1-two2-three3"}
one1-two2-three3-4a -> {"one1-two2-three3", "4a"}
one1-two2-three3-4a-5a -> {"one1-two2-three3", "4a-5a"}
one1-two2-three3-4a-5a-6a -> {"one1-two2-three3", "4a-5a-6a"}
one1-two2-three3-4a-5a-6a-7a -> {"one1-two2-three3", "4a-5a-6a-7a"}
one1-two2-three3-4a-5a-6a-7a-8a -> {"one1-two2-three3", "4a-5a-6a-7a-8a"}
one1_two2 -> NO MATCH
0 голосов
/ 04 мая 2018

Вам не нужно слишком усложнять вещи, чтобы обойти проблему:

(?m)^(\w+(?:-\w+){0,2})(?:-(\w+(?:-\w+)*))?$

(?m) включает многострочный флаг, который заставляет якоря ^ и $ соответствовать началу и концу каждой строки соответственно. Совпадение начинается с совпадения символов слова \w+, затем до двух дополнительных шаблонов -\w+, которые формируют информацию о первой группе захвата.

Вторая группа захвата содержит все, что будет после. Если вы уверены в форматировании, вы можете сделать это тоже:

(?m)^(\w+(?:-\w+){0,2})(.+)?$

Проверьте это на демоверсия

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...