Регулярное выражение для определения заявлений - PullRequest
5 голосов
/ 16 марта 2009

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

if (condition_function(params)) {
     statements;
}

Мое выражение для захвата всех операторов if, кроме следующих:

 if\s*\(([^\(\)]|\s)*\)\s*{(.|\s)*?}

Кто-нибудь знает, как это написать?

Ответы [ 8 ]

13 голосов
/ 16 марта 2009

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

Взгляните на WP: Формальная теория языка это вас интересует ...

Btw. Вы даже не можете проверить выражение, состоящее только из скобок, если оно правильно ([[][]] верно, но []][ нет), что является «подзадачей» той, которую вы дали выше.

7 голосов
/ 16 марта 2009

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

if\s*\(((?:[^\(\)]|\((?1)\))*+)\)\s*{((?:[^{}]|{(?2)})*+)}

Единственная проблема, с которой следует столкнуться сейчас, - это если в операторе if есть оператор if.

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

Обновление: я обнаружил ошибку с указанным выше регулярным выражением. Он не перехватывает операторы if, которые содержат строки с несоответствующими круглыми скобками в их разделах условия или оператора. Как в следующем примере:

if (var1 == "("){
    echo "{";
}

Однако это допустимое утверждение if. Решение:

if\s*\(((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^\(\)]|\((?1)\))*+)\)\s*{((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^{}]|{(?2)})*+)}\s*

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

ОБНОВЛЕНИЕ: у меня теперь есть, чтобы он захватывал операторы else и else if, которые прикреплены к операторам if. Единственная проблема состоит в том, что возвращаемые им группы захвата являются последними и последними, если в операторе if. Надеюсь, я разберусь, как обойти это.

if\s*\(((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^\(\)]|\((?1)\))*+)\)\s*{((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^{}]|{(?2)})*+)}\s*(?:(?:else\s*{((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^{}]|{(?3)})*+)}\s*)|(?:else\s*if\s*\(((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^\(\)]|\((?4)\))*+)\)\s*{((?:(?:(?:"(?:(?:\\")|[^"])*")|(?:'(?:(?:\\')|[^'])*'))|[^{}]|{(?5)})*+)}\s*))*;

Если вы хотите проверить это, вот отличный сайт для этого: http://gskinner.com/RegExr/

5 голосов
/ 16 марта 2009

Вы пытаетесь написать регулярное выражение для разбора нерегулярного языка? Это никогда не полетит.

3 голосов
/ 16 марта 2009

Вам нужно написать код на полном языке Тьюринга. Существуют инструменты, которые могут автоматически создавать код для вас, например Flex . Однако, если у вас есть простая проблема, вероятно, проще всего просто написать какой-нибудь простой код для разбора. Вот пример кода C #, который может помочь вам начать.

public void TestIf()
    {
      var s = @"if (condition_function(params)) {
     statements;
       }";
      var ifRegex = @"if *\(.*\) *{.*}";
      if (Regex.IsMatch(s, ifRegex, RegexOptions.Singleline))
      {
        var firstParens = s.IndexOf('(');
        if (firstParens != -1)
        {
          var conditionPart = s.Skip(firstParens + 1);
          int stack = 1;
          int lastParens = -1; 
          while(stack > 0)
          {
            for (int i = 0; i < conditionPart.Count(); i++)
            {
              var c = conditionPart.ElementAt(i);
              if (c == '(')
              {
                stack++;
              }
              if (c == ')')
              {
                stack--;
              }
              if (stack == 0)
              {
                lastParens = i;
                break; 
              }
            }
          }
          if (lastParens != -1)
          {
            var condition = conditionPart.Take(lastParens);
            Console.WriteLine(new string(condition.ToArray()));
          }
        }
      }
    } 
1 голос
/ 16 марта 2009
r = /\bif\s*\(/

txt = <<TXT
if(test)
if (test)
if  (xyz)
; if
print x if(true)
TXT

p txt.scan(r)

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

Кроме того, на каком языке вы пытаетесь сопоставить?

0 голосов
/ 29 декабря 2015

Модифицированное регулярное выражение (Koukaakiva), найти без скобок - https://regex101.com/r/fE6hA5/1 и добавил имена в шаблон

0 голосов
/ 16 марта 2009

быстрый выстрел в него ...

if\s*?\(.*?)\s*?(({?\s*?(.*?;)+\s*?})|(.*?;))
0 голосов
/ 16 марта 2009

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

if\s*\(((?!\s*\{).+)\)\s*\{(.|\s)*?\}

Он использует положительный прогноз ((?!\s*\{).), который гарантирует захват всех до закрытия ) (за исключением случаев, когда в вашем операторе условия есть "{"! Вот где регулярное выражение не может вам помочь)

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