2008-08-29 14 views
8

Estoy trabajando en una base de código C++ que se movió recientemente de X/Motif a Qt. Estoy tratando de escribir un script Perl que reemplace todas las ocurrencias de Boolean (de X) con bool. La secuencia de comandos simplemente hace un reemplazo simple.Regex para reemplazar Boolean con bool

s/\bBoolean\b/bool/g 

Existen algunas condiciones.

1) Tenemos CORBA en nuestro código y \ b coincide con CORBA :: Boolean que debería no cambiarse.
2) No debe coincidir si se encontró como una cadena (es decir, "booleano")

Actualizado:

Para # 1, que usa de búsqueda hacia atrás

s/(?<!:)\bBoolean\b/bool/g; 

Para # 2 , Utilicé lookahead.

s/(?<!:)\bBoolean\b(?!")/bool/g</pre> 

Esto muy probablemente funcionará para mi situación, pero ¿qué hay de las siguientes mejoras?

3) No coincide si está en el medio de una cadena (gracias nohat).
4) No coincide si en un comentario. (// o/** /)

+0

nota al margen: http://stackoverflow.com/questions/72312/how-should-i-capitalize-perl#72757 – szabgab

Respuesta

0

Fijar condición 1 intento:

s/[^:]\bBoolean\b(?!")/bool/g 

El [^:] dice para que coincida con cualquier carácter que no sea ":".

1
s/[^:]\bBoolean\b[^"]/bool/g 

Editar: Ratas, golpeado de nuevo. +1 por golpearme, buen señor.

3

s/[^:] \ bBoolean \ b/bool/g

Esto no coincide con cuerdas, donde booleana es por lo que el principio de la línea becuase [^ ("?!): ] es "coincidir con un carácter que no es:"

2

Cuidado con que la afirmación de búsqueda hacia delante cotización en juego que sólo va a partido si de Boole es la última parte de una cadena, pero no en el medio de la.. cadena. Deberá hacer coincidir un número par de comillas que preceden a la coincidencia si desea asegurarse de que no está en una cadena (suponiendo que no haya una línea de varias líneas) s y sin marcas de comillas incrustadas escapadas).

0

3) No coincida si está en el medio de una cuerda (gracias nohat).

Puede escribir un registro para verificar ". * Boolean. *". Pero, ¿qué sucede si tiene una comilla (") dentro de la cadena? Entonces, tiene más trabajo para no excluir (\") patrón.

4) No corresponde si en un comentario. (// o/* * /)

Para '//', puede tener una expresión regular para excluir //.* Pero, mejor sería poner primero una expresión regular para comparar toda la línea para los // comentarios ((. *) (//.*)) y luego aplicar la sustitución solo en $ 1 (primer patrón coincidente).

Para/* * /, es más complejo ya que se trata de un patrón de líneas múltiples. Un enfoque puede ser primero ejecutar todo tu código para hacer coincidir los comentarios de líneas múltiples y luego sacar solo las partes que no coinciden ... algo así como ... (. *) (/*.**/) (. *). Pero, la expresión regular real sería aún más compleja ya que no tendría uno sino más comentarios de varias líneas.

Ahora, ¿qué pasa si tiene/* o */dentro // bloque? (No sé por qué lo tendrías ... pero la ley de Murphy dice que puedes tenerlo). Obviamente hay alguna salida, pero mi idea es enfatizar cuán mal se verá la expresión regular.

Mi sugerencia aquí sería utilizar alguna herramienta léxica para C++ y reemplazar el token booleano con bool. ¿Tus pensamientos?

0

Para evitar escribir un analizador de C completo en perl, está tratando de encontrar el equilibrio. Dependiendo de cuánto cambien las necesidades, me inclinaría a hacer algo así como una s // muy restrictiva y luego cualquier cosa que aún coincida con/Boolean/se escriba en un archivo de excepción para la toma de decisiones humanas. De esta forma, no intentará analizar las cadenas medias C, los comentarios de varias líneas, el texto compilado condicional, etc. que podrían estar presentes.

0
  1. ...
  2. ...
  3. no coinciden si en medio de una cadena (gracias nohat).
  4. No concuerde si en un comentario. (// o/** /)

No se puede hacer con una simple expresión regular. Por eso, es necesario desviar la mirada hacia cada carácter de izquierda a derecha y decidir qué tipo de cosa que es, al menos lo suficiente como para diferenciar los comentarios de los comentarios de varias líneas de cuerdas de otras cosas, y entonces necesita ver si la parte "otras cosas" contiene elementos que desea cambiar.

Ahora, no sé las reglas sintácticas exactas de comentarios y cadenas en C++ por lo que el siguiente va a ser imprecisa y completamente undebugged, pero te dará una idea de la complejidad que estás haciendo en contra.

my $line_comment  = qr! (?> // .* \n?) !x; 
my $multiline_comment = qr! (?> /\* [^*]* (?: \* (?: [^/*] [^*]*)?)*)* \*/) !x; 
my $string   = qr! (?> " [^"\\]* (?: \\ . [^"\\]*)* ") !x; 
my $boolean_type  = qr! (?<!:) \b Boolean \b !x; 

$code =~ s{ \G (
     $line_comment 
    | $multiline_comment 
    | $string 
    | ($boolean_type) 
    | . 
) }{ 
    defined $2 ? 'bool' : $1 
}gex; 

Por favor, no me pregunte a explicar esto en todas sus complejidades, que me llevaría un día y otro. Simplemente compre y lea Jeff   Friedl's Mastering Regular Expressions si quiere entender exactamente qué está pasando aquí.

0

El " 'booleano' en medio de una cadena" suena un poco improbable parte, me gustaría comprobar primero si hay alguna ocurrencia de la misma en el código con algo como

m/"[^"]*Boolean[^"]*"/ 

Y si hay es ninguno o pocos, simplemente ignore ese caso.

1
#define Boolean bool 

Deje el preprocesser hacerse cargo de esto. Cada vez que veas un booleano, puedes arreglarlo manualmente o esperar que una expresión regular no se confunda. Dependiendo de la cantidad de macros que use, puede descargar el cpp.

Cuestiones relacionadas