Разбор подписей с регулярным выражением, имеющий "забаву" с возвращаемыми значениями массива
У меня есть это [противное] регулярное выражение для захвата сигнатуры процедуры VBA со всеми частями в ведре:
public static string ProcedureSyntax
{
get
{
return
@"(?:(?<accessibility>Friend|Private|Public)\s)?(?:(?<kind>Sub|Function|Property\s(Get|Let|Set)))\s(?<identifier>(?:[a-zA-Z][a-zA-Z0-9_]*)|(?:\[[a-zA-Z0-9_]*\]))\((?<parameters>.*)?\)(?:\sAs\s(?<reference>(((?<library>[a-zA-Z][a-zA-Z0-9_]*))\.)?(?<identifier>([a-zA-Z][a-zA-Z0-9_]*)|\[[a-zA-Z0-9_]*\]))(?<array>\((?<size>(([0-9]+)\,?\s?)*|([0-9]+\sTo\s[0-9]+\,?\s?)+)\))?)?";
}
}
Отчасти это избыток и будет соответствовать нелегальным синтаксисам массивов (в контексте сигнатуры процедуры), но это не мое беспокойство прямо сейчас.
Проблема в том, что эта часть:
\((?<parameters>.*)?\)
ломается, когда функция (или свойство getter) возвращает массив, потому что тогда подпись будет выглядеть примерно так:
Public Function GetSomeArray() As Variant()
Или вот так:
Public Function GetSomeArray(ByVal foo As Integer) As Variant()
И это делает тип возвращаемой функции полностью запутанным, потому что группа захвата parameters
получит это:
ByVal foo As Integer) As Variant(
Я знаю, почему это происходит - потому что мое регулярное выражение принимает последнюю закрывающую фигуру, которая ограничивает группу захвата parameters
.
Есть ли способ исправить мое регулярное выражение, чтобы изменить это, не слишком сильно влияя на производительность?
Ловушка заключается в том, что это допустимая подпись:
Public Function DoSomething(foo As Integer, ParamArray bar()) As Variant()
У меня есть другое отдельное регулярное выражение для обработки отдельных параметров, и это будет отлично работать... если этот не запутался с типами возврата массива.
Это то, что я получаю:
![enter image description here]()
Что мне нужно, это группа parameters
, которая не включает в себя часть ) As Variant(
, например, когда тип возвращаемого значения не является массивом:
![enter image description here]()
Ответы
Ответ 1
Здесь вы идете....
(?:(?<accessibility>Friend|Private|Public)\s)?(?:(?<kind>Sub|Function|Property\s(Get|Let|Set)))\s(?<identifier>(?:[a-zA-Z][a-zA-Z0-9_]*)|(?:\[[a-zA-Z0-9_]*\]))\((?<parameters>(?:\(\)|[^()])*)?\)(?:\sAs\s(?<reference>(((?<library>[a-zA-Z][a-zA-Z0-9_]*))\.)?(?<identifier1>([a-zA-Z][a-zA-Z0-9_]*)|\[[a-zA-Z0-9_]*\]))(?<array>\((?<size>(([0-9]+)\,?\s?)*|([0-9]+\sTo\s[0-9]+\,?\s?)+)\))?)?
DEMO
Каковы изменения, внесенные в исходное регулярное выражение?
Я просто изменил эту часть \((?<parameters>.*)?\)
в исходном регулярном выражении на \((?<parameters>(?:\(\)|[^()])*)?\)
. То есть .*
в вашем шаблоне сделает жадное соответствие до последнего символа )
, но этот (?:\(\)|[^()])*
соответствует части ()
или любому символу не (
или )
ноль или более раз. так что это соответствует строкам типа foo
или foo()bar
..