2009-03-16 56 views
5

Estoy tratando de escribir una expresión regular para identificar una instrucción if. El único problema que tengo es obtenerlo si las declaraciones tienen paréntesis entre paréntesis. Por ejemplo:Expresión regular para identificar declaraciones if

if (condition_function(params)) { 
    statements; 
} 

Mi expresión para capturar todos los estados excepto si éstos es:

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

¿Alguien sabe cómo se escribe eso?

+0

@Koukaakiva - La corrección de los mensajes de errores de ortografía es un campo común aquí en la SO. Las preguntas frecuentes tienen más detalles sobre esta práctica. http://stackoverflow.com/faq –

Respuesta

5

Creo que esto puede funcionar. Si alguien ve algo que yo no veo, como una razón por la que no funcionará, por favor responde.

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

El único problema que esto debería encontrar ahora es si hay una instrucción if en una instrucción if.

He probado esto en cada sentencia if válida que puedo pensar que podría romperla y lo único que no funciona es una que contiene una cadena con un paréntesis sin igual.

Actualización: Encontré un error con la expresión regular anterior. No detecta si las instrucciones que contienen cadenas con paréntesis no coincidentes en sus secciones de condición o enunciado. Como en el siguiente ejemplo:

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

Sin embargo, esta es una declaración if válida.La solución:

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

Esta expresión regular captura todo si las declaraciones incluso los que contienen cadenas con paréntesis sin igual.

ACTUALIZACIÓN: Ahora lo tengo para que se capture el else y si las declaraciones que se adjuntan a las declaraciones if. El único problema es que los grupos de captura que devuelve son el último y el último si está en la instrucción if. Espero poder resolverlo también.

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

Si desea probarlo, aquí hay un gran sitio web para ello: http://gskinner.com/RegExr/

+1

Aún no captará todo, porque no está usando un analizador real. Como solo un ejemplo trivial, esto coincidirá con una cadena literal como x = "if (x) {y;}"; – Ken

+0

Eso es exactamente lo que estoy tratando de hacer. Esto se está utilizando para un motor de análisis alternativo para mediaWiki. Como esto encuentra sentencias if, podré sacarlas y ejecutarlas como si fueran enunciados en mi código. – Koukaakiva

+0

Increíble. Te daré +1, pero espero que nunca vea esto en ningún código que tenga que tocar. Para obtener puntos extra, tradúzcalo a brainf ** k – erikkallen

13

Eso no es posible con expresiones regulares ya que las expresiones regulares solo pueden coincidir con los lenguajes regulares y la que está tratando de analizar no tiene contexto y no regular (gracias a dirkgently y dmckee).

Tenga una mirada en WP: Formal language theory es que está interesado ...

BTW. Ni siquiera puede verificar una expresión hecha solo entre paréntesis si es correcta ([[][]] es correcta, pero []][ no), que es un "subproblema" del que proporcionó anteriormente.

+0

Cada idioma normal no tiene ningún contexto. – dirkgently

+0

+1, pero arregle la nit que escogió dirkgently ... – dmckee

+0

dirkgently, cierto pero no al revés. –

0

Si usted tiene que utilizar una expresión regular a pesar de que nunca se pondrá al día todos casos, éste es mejor:

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

Se utiliza un positive lookahead ((?!\s*\{).) que aseguran captar todo hasta el cierre ) (excepto si su estado de condición tiene un "{" en él! Aquí es donde la expresión regular no puede ayudarle)

5

¿Está tratando de escribir una expresión regular para analizar un idioma no habitual? Eso nunca volará.

+0

Si no son expresiones regulares, ¿qué sugeriría para analizar este lenguaje no habitual? – Koukaakiva

+0

Su compilador usa un lexer seguido de un análisis sintáctico. Si solo necesita identificar sentencias if y no puede usar un analizador existente, probablemente pueda escribir un analizador descendente recursivo sin demasiados problemas. – Ken

0

un tiro rápido en ello ...

if\s*?\(.*?)\s*?(({?\s*?(.*?;)+\s*?})|(.*?;)) 
1
r = /\bif\s*\(/ 

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

p txt.scan(r) 

si (algo) .. algo puede ser cualquier cosa .. si hay una cadena con un paréntesis de poner fin a su interior y que quieren tratar correctamente con los pares de paréntesis que coinciden, entonces terminará rápidamente con una gran expresión regular.

¿También con qué idioma está tratando de hacer frente?

+0

Estoy intentando construir un analizador sintáctico para el motor mediaWiki que se adapta mejor al proyecto en el que estoy trabajando. Una de las cosas con las que nos encontramos continuamente es la necesidad de declaraciones if. La extensión mediaWiki para las declaraciones if tampoco coincide con lo que necesitamos. – Koukaakiva

+0

así que si entiendo que está correcto (no sé mediawiki) ... ¿necesita partes opcionales en el margen, que se pueden habilitar/deshabilitar? – neoneye

+0

si solo necesitas extraer sentencias if, entonces puedes usar regex. Sin embargo, para la tarea, creo que debes escribir tu propio analizador. Regex no puede resolverlo solo. No es una tarea fácil, buena suerte. – neoneye

3

tiene que escribir código en un lenguaje Turing completo. Existen herramientas que pueden construir automáticamente el código para usted, como Flex. Sin embargo, si tiene un problema simple, probablemente sea más fácil simplemente escribir un código de análisis simple. Aquí hay un ejemplo de código C# que podría ayudarlo a comenzar.

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())); 
      } 
     } 
     } 
    } 
+0

Esto es muy útil. Al mirar otras partes de mi código, me doy cuenta de que debo cambiar a algo como esto. Y este código probablemente me ahorrará mucho tiempo. Gracias. – Koukaakiva

+0

Y también es posible que deba contabilizar cadenas y comentarios que pueden contener corchetes. – pro3carp3

+0

Probablemente desee quitar los comentarios en un paso anterior. ¡No olvide tratar con comentarios anidados! – RossFabricant