Regex не соответствует подгруппам, как ожидалось

Я пишу программу на C, которая использует регулярное выражение для обнаружения такой строки:

гл###

Где # указывает целое число. Здесь должно быть зафиксировано до 11 целочисленных значений.

Чтобы удовлетворить эту потребность, я написал следующее регулярное выражение (и ниже я предоставил образец значения):

#define HARDLINK_MATCH_EXPRESSION "^hl( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*( ([1-9][0-9]*))*"
char *sampleValue = "hl 1 2 3 4 5 6 7 8 9 10 11" ;

Однако и в программе C, и в https://regex101.com/ я обнаружил, что строка совпадает, но «захватывается» только одно целое число (последнее). Я думаю, что это определяет серию из одиннадцати жадных «внешних» групп, и я ожидал, что каждая группа будет удовлетворена этим примером.

Я изучил бесчисленное количество решений такого рода проблем, и хотя я уверен, что мой вопрос, вероятно, не уникален, я не смог найти совпадения среди множества ответов.

Может кто-нибудь объяснить, почему выражение не захватывает внутренние группы так же, как и конечные (пока выражение не закончится при 11 захватах)??

РЕДАКТИРОВАТЬ

Хотя мне по-прежнему хотелось бы получить ответ на первый вопрос, мой реальный вопрос заключается в том, существует ли способ охватить все группы в выборке.

Спасибо.

При повторении группы захвата будет зафиксировано значение последнего повторения.

The fourth bird 11.07.2024 20:10

Спасибо, я задал неправильный вопрос @Thefourthbird

Dennis 11.07.2024 20:13

Существуют механизмы регулярных выражений, такие как .NET и PyPi для Python, которые имеют коллекцию захватов для получения всех значений группы, но не уверен, есть ли в C библиотека для этого.

The fourth bird 11.07.2024 20:15

Какую библиотеку регулярных выражений вы используете? Это ключевая информация — ответы для POSIX <regex.h> будут отличаться от ответов для PCRE2. Существуют и другие библиотеки регулярных выражений для использования в C. Не забудьте указать, с каким типом регулярных выражений вы работаете.

Jonathan Leffler 11.07.2024 21:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Часть hl( ([1-9][0-9]*))* вашего шаблона соответствует всей строке. Остальная часть шаблона просто соответствует пустым строкам. Итак, у вас есть два захвата, которые соответствуют чему-то другому, кроме пустой строки.

Изменение каждого ( ([1-9][0-9]*))* на ( ([1-9][0-9]*))? решило бы проблему. Однако я бы написал шаблон следующим образом:

^
hl
(?:
   [ ] (0|[1-9][0-9]*)
   (?:
      [ ] (0|[1-9][0-9]*)
      (?:
         [ ] (0|[1-9][0-9]*)
         (?:
            [ ] (0|[1-9][0-9]*)
            (?:
               [ ] (0|[1-9][0-9]*)
               (?:
                  [ ] (0|[1-9][0-9]*)
                  (?:
                     [ ] (0|[1-9][0-9]*)
                     (?:
                        [ ] (0|[1-9][0-9]*)
                        (?:
                           [ ] (0|[1-9][0-9]*)
                           (?:
                              [ ] (0|[1-9][0-9]*)
                              (?:
                                 [ ] (0|[1-9][0-9]*)
                              )?
                           )?
                        )?
                     )?
                  )?
               )?
            )?
         )?
      )?
   )?
)?

Я написал это так, как будто пробелы разрешены (согласно флагу x в некоторых движках) для удобства чтения. Если у вас нет такой роскоши, она сжимается до следующего:

^hl(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*)(?: (0|[1-9][0-9]*))?)?)?)?)?)?)?)?)?)?)?

Примечания:

  • Я удалил лишние захваты. У вас было вдвое больше, чем хотелось.
  • Использование (?: [ ] (0|[1-9][0-9]*) (?: ... )? )? вместо (?: [ ] (0|[1-9][0-9]*) )? (?: ... )? имеет больше смысла и может значительно сократить количество возвратов при неудачном совпадении.
  • Я изменил шаблон, чтобы разрешить 0. Замените 0|[1-9][0-9]* на [1-9][0-9]*, чтобы продолжить запрет.

Великолепно! Спасибо! Я помещу его в программу так, как вы его написали, затем вытащу символы новой строки и их пробелы с помощью кода - то, как вы это написали, делает его кристальным (и не подверженным опечаткам и т. д.). Это высокое качество!

Dennis 11.07.2024 20:37

Будьте осторожны и не удалите пространство, которое хотите сохранить. Возможно, вы сможете использовать \h (или даже \h+), \s (или даже \s+) или \x20 вместо [ ], чтобы обойти эту проблему. Ваш движок может поддерживать или не поддерживать их, или он может использовать другой синтаксис. Однако осторожно. \h соответствует любому горизонтальному символу пробела (т.е. включает табуляцию и другие символы), а \s соответствует любому символу пробела (т.е. включает табуляцию, перевод строки и т. д.). И не забудьте экранировать \ в строковом литерале.

ikegami 11.07.2024 20:41

Спасибо, да. Я пишу функцию для удаления новой строки и всех пробелов после нее, пока не исчезнут пробелы. Все будет хорошо. (Хотя я думаю, что приму план \x20. Все равно думал об этом.

Dennis 11.07.2024 20:47

Ваше тестовое выражение соответствует только этой части вашего регулярного выражения: ^hl( ([1-9][0-9]*))*. Это не оставляет ничего для других групп захвата, которые можно было бы сопоставить или захватить, и это нормально, если речь идет о данном регулярном выражении. Таким образом, в конечном итоге вы получаете только группы 1 и 2, которые что-либо захватывают.

Более того, когда с помощью количественной оценки группа захвата в регулярном выражении сопоставляет входные данные несколько раз, фиксируется только последнее совпадение. Следовательно, в этом случае группа 1 захватит «11», а группа 2 захватит «11».

Возможно, вы используете неверный квантификатор. * приведет к тому, что группа, определенная таким образом, будет соответствовать неограниченному количеству раз, но ? приведет к тому, что она будет соответствовать не более одного раза (в большинстве диалектов регулярных выражений; вы не сказали, какой из них вы используете). Таким образом, это может быть больше того, что вам нужно:

#define HARDLINK_MATCH_EXPRESSION "^hl( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?( ([1-9][0-9]*))?"

Это решает проблему, но у него вдвое больше захватов, чем необходимо, он может работать очень плохо, если линия не совпадает, и не принимает 0 (что может быть намеренно, а может и нет).

ikegami 11.07.2024 20:31

@ikegami, представленная здесь альтернатива соответствует точно тем же строкам, что и ОП, не больше и не меньше, вплоть до ограничения на желаемое количество захватов. Он структурирует захваты так же, как это делает ОП, что может быть, а может и не быть тем, чего они хотят, но это то, о чем они спрашивали. И это может быть или не быть больше захватов, чем необходимо. Не все диалекты регулярных выражений распознают группы без захвата.

John Bollinger 11.07.2024 20:37

Re «Он структурирует захваты, как это делает ОП», Совсем нет. Вопрос в том, чтобы запечатлеть правильные вещи. Вы изменили структуру захватов, но возможно недостаточно. Хотя иметь дополнительные захваты не так уж и плохо, и это можно обойти, скорее всего, это неправильно. Я просто указал на это. /// Не принимать 0 тоже, скорее всего, неправильно. Я просто указал на это. /// Однако нет причин для чрезмерного возврата.

ikegami 11.07.2024 20:49

Другие вопросы по теме