регулярное выражение lookaround - PullRequest
1 голос
/ 08 января 2009

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

Я пытаюсь выполнить массивный поиск и замену кода C #, используя регулярные выражения .NET. То, что я хочу сделать, это найти строку кода, где определенная функция вызывается для переменной типа DateTime. например:

axRecord.set_Field("CreatedDate", m_createdDate);

и я бы знал, что это переменная DateTime, b / c ранее в этом кодовом файле будет строка:

DateTime m_createdDate;

но кажется, что я не могу использовать именованную группу в негативном виде, например:

(?<=DateTime \k<1>.+?)axRecord.set_[^ ]+ (?<1>[^ )]+)

и если я попытаюсь сопоставить весь текст между объявлением переменной и вызовом функции следующим образом:

DateTime (?<1>[^;]+).+?axRecord.set.+?\k<1>

он найдет первое совпадение - сначала на основе первой объявленной переменной - но затем не сможет найти другие совпадения, потому что код выложен так:

DateTime m_First;
DateTime m_Second;
...
axRecord.set_Field("something", m_First);
axRecord.set_Field("somethingElse", m_Second);

и первое совпадение включает в себя объявление второй переменной.

Есть ли хороший способ сделать это только с помощью регулярных выражений, или я должен прибегнуть к скриптингу в моей логике?

Ответы [ 5 ]

5 голосов
/ 08 января 2009

Посмотрите на мой ответ на этот вопрос Получить содержимое методов из файла C #

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

Я знаю, что это не ответ RegEx, но я не думаю, что RegEx - это ответ.

1 голос
/ 08 января 2009

Это будет трудно сделать с помощью одного выражения регулярного выражения. Однако это можно сделать, если вы рассматриваете обработку строк с небольшим количеством состояния.

Примечание: я не могу точно сказать, что вы пытаетесь сопоставить в строке axRecord, поэтому вам, вероятно, придется соответствующим образом настроить это регулярное выражение.

void Process(List<string> lines) {
  var comp = StringComparer.Ordinal;
  var map = new Hashset<string>comp);
  var declRegex = new Regex("^\s(?<type>\w+)\s*(?<name>m_\w+)\s*";);
  var toReplaceRegex = new Regex("^\s*axRecord.set_(?<toReplace>.*(?<name>m_\w+).*)");

  for( var i = 0; i < lines.Length; i++) {
    var line = lines[i];
    var match = declRegex.Match(line);
    if ( match.Success ) {
      if ( comp.Equals(match.Groups["type"], "DateTime") ) {
        map.Add(comp.Groups["name"]);
      } else {
        map.Remove(comp.Groups["name"]);
      }
      continue;
    }

    match = toReplaceRegex.Match(line);
    if ( match.Success && map.Contains(match.Groups["name"]) ) {
      // Add your replace logic here
    }
}
0 голосов
/ 09 января 2009

Попробуйте это:

@"(?s)set_Field\(""[^""]*"",\s*(?<vname>\w+)(?<=\bDateTime\s+\k<vname>\b.+)"

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

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

0 голосов
/ 08 января 2009

Это странно. Мне удалось построить регулярное выражение, которое его находит, но оно соответствует только первому.

(?<=private datetime (?<1>\b\w+\b).+?)set_field[^;]+?\k<1>

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

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

Кто-нибудь знает что-нибудь об этом, или я говорю сумасшедший?

0 голосов
/ 08 января 2009

Это невозможно сделать с помощью регулярных выражений. С одной стороны, грамматика C # не является регулярной; но что более важно, вы говорите об анализе выражений, которые лексически не связаны. Для такого рода вещей вам понадобится полный семантический анализ. Это означает, что лексер, парсер, привязка имени и, наконец, проверка типов. Получив аннотированный AST, вы можете найти нужное поле и просто прочитать его тип.

Я предполагаю, что это намного больше работы, чем вы хотите, хотя, учитывая, что это примерно половина полноценного компилятора C #.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...