Я пишу программу на 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 захватах)??
РЕДАКТИРОВАТЬ
Хотя мне по-прежнему хотелось бы получить ответ на первый вопрос, мой реальный вопрос заключается в том, существует ли способ охватить все группы в выборке.
Спасибо.
Спасибо, я задал неправильный вопрос @Thefourthbird
Существуют механизмы регулярных выражений, такие как .NET и PyPi для Python, которые имеют коллекцию захватов для получения всех значений группы, но не уверен, есть ли в C библиотека для этого.
Какую библиотеку регулярных выражений вы используете? Это ключевая информация — ответы для POSIX <regex.h> будут отличаться от ответов для PCRE2. Существуют и другие библиотеки регулярных выражений для использования в C. Не забудьте указать, с каким типом регулярных выражений вы работаете.
Часть 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]*
, чтобы продолжить запрет.Великолепно! Спасибо! Я помещу его в программу так, как вы его написали, затем вытащу символы новой строки и их пробелы с помощью кода - то, как вы это написали, делает его кристальным (и не подверженным опечаткам и т. д.). Это высокое качество!
Будьте осторожны и не удалите пространство, которое хотите сохранить. Возможно, вы сможете использовать \h
(или даже \h+
), \s
(или даже \s+
) или \x20
вместо [ ]
, чтобы обойти эту проблему. Ваш движок может поддерживать или не поддерживать их, или он может использовать другой синтаксис. Однако осторожно. \h
соответствует любому горизонтальному символу пробела (т.е. включает табуляцию и другие символы), а \s
соответствует любому символу пробела (т.е. включает табуляцию, перевод строки и т. д.). И не забудьте экранировать \
в строковом литерале.
Спасибо, да. Я пишу функцию для удаления новой строки и всех пробелов после нее, пока не исчезнут пробелы. Все будет хорошо. (Хотя я думаю, что приму план \x20. Все равно думал об этом.
Ваше тестовое выражение соответствует только этой части вашего регулярного выражения: ^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, представленная здесь альтернатива соответствует точно тем же строкам, что и ОП, не больше и не меньше, вплоть до ограничения на желаемое количество захватов. Он структурирует захваты так же, как это делает ОП, что может быть, а может и не быть тем, чего они хотят, но это то, о чем они спрашивали. И это может быть или не быть больше захватов, чем необходимо. Не все диалекты регулярных выражений распознают группы без захвата.
Re «Он структурирует захваты, как это делает ОП», Совсем нет. Вопрос в том, чтобы запечатлеть правильные вещи. Вы изменили структуру захватов, но возможно недостаточно. Хотя иметь дополнительные захваты не так уж и плохо, и это можно обойти, скорее всего, это неправильно. Я просто указал на это. /// Не принимать 0
тоже, скорее всего, неправильно. Я просто указал на это. /// Однако нет причин для чрезмерного возврата.
При повторении группы захвата будет зафиксировано значение последнего повторения.