2010-01-28 2 views
3

Может ли кто-нибудь помочь мне разобрать, следуя из декларации метода C#: scope, isStatic, имя, тип возврата и список параметров и их типов. Таким образом, данный метод декларируется следующим образом:Regex: анализ объявления метода C#

public static SomeReturnType GetSomething(string param1, int param2) 

и т. Д. Мне нужно уметь разбирать его и получать информацию выше. Так что в этом случае

  • имя = "GetSomething"
  • сфера = "общественного"
  • isStatic = истинный
  • ReturnType = "SomeReturnType"

, а затем массив типа параметров и пар имен.

Ой почти забыл самую важную часть. Он должен учитывать все другие области (защищенные, частные, внутренние, защищенные внутренние), отсутствие «статического», недействительного типа возврата и т. Д.

Обратите внимание, что REFLECTION здесь не является решением. Мне нужен REGEX.

До сих пор у меня есть эти два:

(?:(?:public)|(?:private)|(?:protected)|(?:internal)|(?:protected internal)\s+)* 

(?:(?:static)\s+)* 

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

+0

Я не думаю, что отражение, чтобы это работало, вы смотрите на источник кода, но не имеете доступа к скомпилированной сборке этого кода? –

+0

Да, на самом деле у меня есть код, но я создаю из него метаданные. – epitka

+0

Отражение может быть гораздо более простым, тогда я отправлю пример. –

ответ

0

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

Если вы проданы в исключительном выражении, вам нужно использовать регулярное выражение, которое использует группировку, внешний вид и внешний вид.

http://www.regular-expressions.info/lookaround.html

Даже при ограниченном объеме, что вы пытаетесь разобрать его, вам понадобятся еще некоторые очень конкретные рекомендации по всем возможностям.

+0

Я в порядке с несколькими регулярными выражениями. – epitka

1

Я бы не стал использовать Regex. Когда вы переходите на часть параметров метода интерпретации, он становится очень грязным (например, ref и out). Я не знаю, нужна ли вам поддержка нотации атрибутов, но это создало бы полный беспорядок.

Возможно, библиотека синтаксического анализатора C# может помочь. Я нашел несколько в Интернете:

В качестве альтернативы, вы могли бы сначала накормить код компилятора во время выполнения, а затем использовать отражение на вновь созданной сборке. Он будет медленнее, но в значительной степени гарантированно будет правильным. Несмотря на то, что вы, кажется, против идеи использования рефлексии, это может быть жизнеспособным решением.

Что-то вроде этого:

List<string> referenceAssemblies = new List<string>() 
{ 
    "System.dll" 
    // ... 
}; 

string source = "public abstract class TestClass {" + input + ";}"; 

CSharpCodeProvider codeProvider = new CSharpCodeProvider(); 

// No assembly name specified 
CompilerParameters compilerParameters = 
    new CompilerParameters(referenceAssemblies.ToArray()); 
compilerParameters.GenerateExecutable = false; 
compilerParameters.GenerateInMemory = false; 

CompilerResults compilerResults = codeProvider.CompileAssemblyFromSource(
    compilerParameters, source); 

// Check for successful compilation here 

Type testClass = compilerResults.CompiledAssembly.GetTypes().First(); 

Затем с помощью отражения на testClass.

Компиляция должна быть безопасной без проверки ввода, поскольку вы не выполняете какой-либо код. Вам понадобятся только очень простые проверки, например, убедитесь, что введена только одна сигнатура метода.

+0

'ref' и 'out' также не поддерживаются. – epitka

6

Некоторые мысли о вашей проблеме:

Набор строк, которые могут быть подкреплен конкретным регулярным выражением называется регулярным языком. Набор строк, которые являются легальными декларациями метода, - , а не - обычный язык в любой версии C#. Если вы пытаетесь найти регулярное выражение, которое соответствует , каждый законный декларация метода C# и отклоняет каждые незаконное объявление метода C#, тогда вам не повезло.

В целом, регулярные выражения почти всегда являются плохими идеями для чего угодно, кроме простейших проблем совпадения. (Извините, Джефф.) Намного лучше всего сначала написать лексер , который разбивает строку на последовательность tokens. Затем проанализируйте последовательность токенов. (Использование регулярных выражений как часть лексера - не страшная идея, хотя вы можете обойтись без них.)

Я также отмечаю, что вы анализируете довольно много осложнений в объявлениях метода синтаксического анализа. Вы не упомянули:

  • общих/массив/указателя/обнуляемый возвратный и формального параметр типа
  • общих декларации параметров типа
  • общих ограничения параметров типа
  • небезопасного/ехЬегпа/новый/переопределение/виртуальный// запечатанные абстрактные методы
  • явных методы реализации интерфейса
  • метод/параметр/возврат атрибуты
  • частичных методов - немного сложно разобрать, частичный являются контекстным ключевым словом
  • комментариев

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

Почему вы хотите это сделать в первую очередь? Делать это правильно - довольно много работы. Возможно, есть более простой способ получить то, что вы хотите?

+0

+1 для lexer :) – GalacticCowboy

+0

Спасибо Эрику за такое подробное сообщение о проблемах, с которыми я мог столкнуться, но ни одно из осложнений, о которых вы говорите, должно быть обработано вообще, поскольку в этом сценарии они просто недействительны (я разъяснил это в области комментариев, мой плохой). Мне не нужно гарантировать, что подпись метода хороша вообще, так как она не сработает во время компиляции. Я думаю, что с этими двумя регулярными выражениями над небольшим количеством строк я буду в порядке. – epitka

+0

Что касается более простого способа, я не думаю, что другой, тогда создаю фиктивный класс, компилируя его в отдельный домен приложения, а затем размышляя над ним и т. Д., Но это просто избыток для того, что мне нужно здесь. И все это должно работать в веб-среде в условиях среднего доверия. – epitka

0
string test = @"public static SomeReturnType GetSomething(string param1, int param2)"; 
var match = Regex.Match(test, @"(?<scope>\w+)\s+(?<static>static\s+)?(?<return>\w+)\s+(?<name>\w+)\((?<parms>[^)]+)\)"); 
Console.WriteLine(match.Groups["scope"].Value); 
Console.WriteLine(!string.IsNullOrEmpty(match.Groups["static"].Value)); 
Console.WriteLine(match.Groups["return"].Value); 
Console.WriteLine(match.Groups["name"].Value); 
List<string> parms = match.Groups["parms"].ToString().Split(',').ToList(); 
parms.ForEach(x => Console.WriteLine(x)); 
Console.Read(); 

Разбивается на парты запятыми, но вполне возможно также справиться с этим.

0
(?<StringRepresentation>\A\s*(?:(?:(?<Comment>(?://.*\n)|(?:/\*(?:[\w\[email protected]#$%^&*()\[\]<>,.;\\"':|{}`~+=-_?\s]*)?\*/))|(\[\s*(?<Attributes>\w*)[^\[\]]*?\]))\s*)*?(?:(?:(?<Access>protected\s+internal|internal\s+protected|private|public|protected|internal)\s+)?(?:(?<InheritanceModifier>new|abstract|override|virtual)\s+)?(?:(?<Static>static)\s+)?(?:(?<Extern>extern)\s+)?(?:partial\s+)?)+(?:(?<Type>\w+(?:[\w,.\?\[\]])*?(?:\<.*>)*?)\s+)?(?<Operator>operator\s+)?\s*(?<Name>~?(?:[\w\=+\-\!\~\d\.])+?)\s*(?:\<(?:\w\.*\d*\,*\s*)+\>)*\s*\((?<Parameters>(?:[^()])*?)\)\s*(?:where\s+.+)?\s*(?:\:\s*(?:this|base)\s*(?:\(?[^\(\)]*(?:(?:(?:(?<OpenC>\()[^\(\)]*)+(?:(?<CloseC-OpenC>\))[^\(\)]*?)+)*(?(OpenC)(?!))\)))\s*)?(?:;|(?<ah>\{[^\{\}]*(?:(?:(?:(?<Open>\{)[^\{\}]*)+(?:(?<Close-Open>\})[^\{\}]*?)+)*(?(Open)(?!))\})))) 

Я не могу лично взять кредит для этого, но парень, который сделал Regionerate (с открытым исходным кодом) придумал это, и она работает очень хорошо для разбора методов в целом.

Смежные вопросы