2010-09-22 13 views
5

Estoy editando un archivo Perl, pero no entiendo esta comparación de expresiones regulares. ¿Puede alguien explicarmelo?

if ($lines =~ m/(.*?):(.*?)$/g) { } .. 

¿Qué ocurre aquí? $lines es una línea de un archivo de texto.

+0

Parece que los primeros '(. *?) 'Coincidirá siempre con cadena vacía. –

+1

No siempre. Coincidirá con todos los personajes hasta los primeros dos puntos. – CanSpice

Respuesta

11

dividirla en partes:

$lines =~ m/ (.*?)  # Match any character (except newlines) 
         # zero or more times, not greedily, and 
         # stick the results in $1. 
      :   # Match a colon. 
      (.*?)  # Match any character (except newlines) 
         # zero or more times, not greedily, and 
         # stick the results in $2. 
      $   # Match the end of the line. 
      /gx; 

lo tanto, esto coincidirá con cadenas como ":" (que coincide con cero caracteres, luego dos puntos, entonces cero caracteres antes del final de la línea, $1 y $2 están vacías cadenas) o "abc:" ($1 = "abc", $2 es una cadena vacía) o "abc:def:ghi" ($1 = "abc" y $2 = "def:ghi").

Y si pasa una línea que no coincide (parece que esto sería si la cadena no contiene dos puntos), entonces no procesará el código que está entre corchetes. Pero si coincide, el código entre corchetes puede usar y procesar las variables especiales $1 y $2 (al menos, hasta que aparezca la siguiente expresión regular, si hay una dentro de los corchetes).

1

(.*?) captura cualquier carácter, pero el menor número de ellos posible.

Por lo tanto, busca patrones como <something>:<somethingelse><end of line>, y si hay múltiples : en la cadena, la primera de ellas se utilizará como el divisor entre <something> y <somethingelse>.

2

Esa línea dice que se realice una coincidencia de expresiones regulares en $lines con la expresión regular m/(.*?):(.*?)$/g. Devolverá efectivamente true si se puede encontrar una coincidencia en $lines y false si no se puede encontrar uno.

Una explicación del operador =~:

binario "= ~" se une una expresión escalar a una coincidencia de patrón. Determinadas operaciones buscan o modifican la cadena $ _ por por defecto. Este operador hace que ese tipo de operación funcione en alguna otra cadena . El argumento correcto es un patrón de búsqueda , sustitución o transliteración. El argumento de la izquierda es lo que se supone que debe buscarse, sustituido o transcrito en su lugar del valor predeterminado $ _. Cuando se utiliza en contexto escalar , el valor de retorno generalmente indica el éxito de la operación .

la expresión regular en sí es:

m/ #Perform a "match" operation 
(.*?) #Match zero or more repetitions of any characters, but match as few as possible (ungreedy) 
:  #Match a literal colon character 
(.*?) #Match zero or more repetitions of any characters, but match as few as possible (ungreedy) 
$  #Match the end of string 
/g #Perform the regex globally (find all occurrences in $line) 

Así que si $lines partidos contra esa expresión regular, que entrarán en la parte condicional, de lo contrario será false y lo saltará.

9

Hay una herramienta para ayudar a comprender las expresiones regulares: YAPE::Regex::Explain.

Ignorando el modificador g, lo que no se necesita aquí:

use strict; 
use warnings; 
use YAPE::Regex::Explain; 

my $re = qr/(.*?):(.*?)$/; 
print YAPE::Regex::Explain->new($re)->explain(); 

__END__ 

The regular expression: 

(?-imsx:(.*?):(.*?)$) 

matches as follows: 

NODE      EXPLANATION 
---------------------------------------------------------------------- 
(?-imsx:     group, but do not capture (case-sensitive) 
         (with^and $ matching normally) (with . not 
         matching \n) (matching whitespace and # 
         normally): 
---------------------------------------------------------------------- 
    (      group and capture to \1: 
---------------------------------------------------------------------- 
    .*?      any character except \n (0 or more times 
          (matching the least amount possible)) 
---------------------------------------------------------------------- 
)      end of \1 
---------------------------------------------------------------------- 
    :      ':' 
---------------------------------------------------------------------- 
    (      group and capture to \2: 
---------------------------------------------------------------------- 
    .*?      any character except \n (0 or more times 
          (matching the least amount possible)) 
---------------------------------------------------------------------- 
)      end of \2 
---------------------------------------------------------------------- 
    $      before an optional \n, and the end of the 
          string 
---------------------------------------------------------------------- 
)      end of grouping 
---------------------------------------------------------------------- 

Ver también perldoc perlre.

+1

¡Eso es condenadamente limpio! –

3

Fue escrito por alguien que sabe demasiado sobre expresiones regulares o no lo suficiente sobre las variables $' y $`.

esto podría haber sido escrita como

if ($lines =~ /:/) { 
    ... # use $` ($PREMATCH) instead of $1 
    ... # use $' ($POSTMATCH) instead of $2 
} 

o

if (($var1,$var2) = split /:/, $lines, 2 and defined($var2)) { 
    ... # use $var1, $var2 instead of $1,$2 
} 
+1

Si desea usar /: /, use la bandera/p y las variables $ {^ PREMATCH} y $ {^ POSTMATCH} de Perl 5.10. Preferiría una división, sin embargo, ya que eso es lo que realmente está sucediendo. –