Ответ 2
Lua не имеет обычного языка регулярного выражения, на его месте есть шаблоны Lua. Хотя они очень похожи на регулярное выражение, шаблоны Lua представляют собой отдельный собственный язык, который имеет более простой набор правил и, самое главное, не имеет функций группировки и чередования.
Интерпретируется как шаблон Lua, пример удивит долгого пользователя регулярного выражения, поскольку многие детали отличаются.
Образцы Lua описаны в PiL, и на первый взгляд они достаточно похожи на обычное регулярное выражение, чтобы вызвать путаницу. Наибольшие различия, вероятно, связаны с отсутствием оператора чередования |
, скобки используются только для отметки захватов, квантификаторы (?
, -
, +
и *
) применяются только к классу символов или символов, а %
- это escape-символ, а не \
. Большой ключ к тому, что этот пример, вероятно, не был написан с учетом Lua, - это отсутствие символа кавычек Lua-шаблона %
, примененного к любому (или, в идеале, всем) не-алфавитно-цифровым символам в строке шаблона, а также к подозрительному использованию из \?
, который пахнет обычным регулярным выражением, чтобы соответствовать одному литералу ?
.
Простой ответ на заданный вопрос: (^?)*
не является рекомендуемой формой и будет соответствовать ^*
или *
, фиксируя присутствие или отсутствие каретки. Если бы это был предполагаемый эффект, я бы написал его как (%^?)%*
, чтобы сделать это более ясным.
Чтобы понять, почему это так, позвольте взять шаблон и проанализировать его как шаблон Lua. Весь шаблон:
^(^?)*\?(.*)$
Отправленный в string.match()
, он будет интерпретироваться следующим образом:
^
привязывает соответствие к началу строки.
(
обозначает начало первого захвата.
^
не находится в начале шаблона или символьного класса, поэтому он соответствует буквенному символу ^
. Для ясности это должно быть написано как %^
.
?
соответствует ровно нулю или одному из предыдущего символа.
)
обозначает конец первого захвата.
*
- это не то, что можно количественно определить, чтобы оно соответствовало буквальному символу *
. Для ясности это должно быть написано как %*
.
\
в шаблоне совпадает с самим собой, это не escape-символ в языке шаблонов. Тем не менее, это символ escape в Lull короткометражном литерале, что делает следующий символ неспецифичным для синтаксического анализатора строк, который в этом случае является спорным, потому что следующий ?
не был особенным для него. Таким образом, если шаблон был заключен в двойные или одинарные кавычки, тогда \
будет поглощаться синтаксическим анализом строк. Если написано в длинной строке (как [[^(^?)*\?(.*)$]]
, обратная косая черта выживет в синтаксическом анализаторе строк, появится в шаблоне.
?
соответствует ровно нулю или одному из предыдущего символа.
(
отмечает начало второго захвата.
.
соответствует любому символу вообще, фактически синоним класса [\000-\255]
(помните, что в числовых экранах Lua в десятичном виде не восьмерично, как в C).
*
с жадностью соответствует нулю или более предыдущего символа.
)
обозначает конец второго захвата.
$
привязывает шаблон к концу строки.
Таким образом, он сопоставляет и фиксирует необязательный ^
в начале строки, а затем *
, а затем необязательный \
, который не был захвачен, и фиксирует всю оставшуюся часть строки. string.match
вернет две строки успеха (либо одна из них может быть нулевой длиной), либо nil
при сбое.
Изменить: Я исправил некоторые опечатки и исправил ошибку в своем ответе, отмеченную Egor в комментарии. Я забыл, что в узорах специальные символы теряют свою особенность, когда в месте, где оно не может применяться. Это означает, что первая звездочка соответствует буквальной звездочке, а не ошибке. Каскад этого большинства проходит.
Обратите внимание, что если вы действительно хотите иметь правильное regexp в Lua, есть библиотеки, которые предоставят его. Тем не менее, встроенный язык шаблонов достаточно мощный. Если этого недостаточно, тогда вам может быть лучше всего использовать полный парсер и использовать LPeg, который может делать все регулярное выражение и Больше. Он даже поставляется с модулем, который предоставляет полный синтаксис regexp, который транслируется в грамматику LPeg для выполнения.