Я не уверен, что рекурсия – это правильный способ охарактеризовать то, что происходит в этом шаблоне, но, к сожалению, я слишком новичок в регулярном выражении, чтобы создать что-то, что будет соответствовать тому, как этот шаблон может меняться и избегать вложенных групп.
Таким образом, шаблон в основном определяется как:
@param {item} {label}:{text} {labeln}:{textn}
где labeln
и textn
– некоторый N экземпляра метки: текстовая группа.
Таким образом, пример будет
/** * * @param name1 test1:this is text for test1 test2:this is text for test2 * @param name2 test3:this is text for test3 test4:this is text for test4 test5:this is text for test5 * * /
Теперь, в идеале, я пытаюсь захватить name1
, test1:this is text for test1
и test2:this is text for test2
как группы соответствия. То же самое касается строки name2
. Конечно, может быть еще много примеров name1
а psuedo «именованные параметры» могут варьироваться от одного до многих. + Изменить: в тексте ярлыка не допускается использование колоний, поскольку они зарезервированы как разделители. Ярлык строго буквенно-цифровой, метка, вероятно, будет ограничена a-zA-Z0-9 _, '"-
Первый вопрос … это проблема рекурсии или я неправильно ее оцениваю?
Второй вопрос: возможно ли это, и если да, то как я могу это достичь?
Предисловие:
Для объяснения я решил уточнить ваши «ярлыки», указав их %
. Это может быть любой зарезервированный символ или другой шаблон, который помогает очистить ярлык / текст:
/** * @param variable_a %label:This is variable: a %required:true * @param variable_b %required:false %pattern:/[a-zA-Z:]/ */
Проблема:
Проблема с захватом повторяющихся шаблонов в регулярных выражениях заключается в том, что у вас не может быть неизвестного количества групп захвата (т.е. вам нужно либо соответствовать глобальному количеству совпадений, либо отображать определенное количество групп в каждом матче):
@param (?# find a param) \s* (?# whitespace) (\w+) (?# capture the variable) \s* (?# whitespace) (?: (?# start non capturing group) %(\w+): (?# capture the label) ([^%\n]+) (?# capture the text) )+ (?# repeat the non-capturing group)
В этом примере я поместил код захвата меток / текста в группу, не связанную с захватом и повторением (1+ раз). Это позволяет нам сопоставить всю строку, но только последний набор меток / текстов захвачен (поскольку у нас есть только 3 группы: переменная, метка и текст).
Прямое решение:
Вместо этого вы можете просто совместить всю строку и затем анализировать строку метки / текста после факта:
(?# match the whole string) @param (?# find a param) \s* (?# whitespace) (\w+) (?# capture the variable) \s* (?# whitespace) (.*) (?# capture the labels/texts) (?# parse the label/text string) % (?# the start of a label) (\w+) (?# capture label) : (?# end of label) ([^%]+) (?# capture text)
Удивительное решение:
Наконец, мы можем использовать магию регулярных выражений для выполнения глобального соответствия всех комбинаций меток и текста. Это означает, что у нас будет определенный набор из 3 групп захвата (переменная, метка, текст), и мы будем иметь переменное количество совпадений. Я думаю, что это лучше всего показать, а затем объяснить, так что вот сумасшедшая удивительная магия регулярных выражений :
(?: (?# start non-capturing group) @param (?# find a param) \s* (?# whitespace) (\w+) (?# capture the variable) \s* (?# whitespace) | (?# OR) \G (?# start back over from our last match) ) (?# end non-capturing group) %(\w+): (?# capture the label) ([^%\n]+) (?# capture the text)
Это вращается вокруг магии PCRE \G
, которая соответствует концу последнего матча. Поэтому мы запускаем группу, не @param
захватом, которая будет содержать «префикс» определения @param
. Это будет либо соответствовать, либо фиксировать переменную OR, начиная с конца нашего последнего совпадения. Затем мы сопоставляем / записываем 1 группу меток / текста. В следующий раз, когда он будет повторен, мы начнем с того места, где мы остановились, группа захвата переменных будет пустой (поскольку она не существует настолько далеко от строки, вам нужно будет использовать логику, чтобы узнать, в какой переменной вы находитесь) и захватить другую метку / текстовую группу (пока мы не нажмем на новую строку, так как я сказал, что текст не может быть %
или \n
). Затем в следующей попытке поиска будет найдена новая переменная, определенная @param
. Я думаю, что это будет ваш лучший вариант, это просто требует больше логики на вашем конце.
Если вы допустите, чтобы ваша средняя метка содержала :
но вы не разрешаете ее на своем конце этикетке, я считаю, что ниже RegEx должен работать достаточно хорошо:
@param\s+(.+?)\s+(.+:.+)\s+([^:]+:[^:]+)$
Однако это не сработает, если ваш шаблон охватывает несколько строк.
Кроме того, если вы пытаетесь разобрать PHPDoc или какой-либо его вариант, вы должны написать свой собственный парсер, используя RegEx.