2009-12-04 29 views
66

Supongamos que tengo:¿Hay un atajo de Perl para contar el número de coincidencias en una cadena?

my $string = "one.two.three.four"; 

¿Cómo debería jugar con el contexto para obtener el número de veces que el patrón encuentra una coincidencia (3)? ¿Se puede hacer esto usando un trazador de líneas único?

yo probamos este:

my ($number) = scalar($string=~/\./gi); 

pensé que al poner paréntesis alrededor de $number, me fuerzo contexto matriz, y por el uso de scalar, me gustaría obtener el recuento. Sin embargo, todo lo que obtengo es 1.

Respuesta

102

Eso pone la expresión regular en contexto escalar, que no es lo que desea. En su lugar, coloque la expresión regular en el contexto de la lista (para obtener el número de coincidencias) y ponga que en contexto escalar.

my $number =() = $string =~ /\./gi; 
+2

Bueno, perlsecret propone "Saturno" como nombre alternativo. :) – oalders

7

Prueba esto:


my $string = "one.two.three.four"; 
my ($number) = scalar(@{[ $string=~/\./gi ]}); 

Devuelve 3 para mí. Al crear una referencia a una matriz, la expresión regular se evalúa en el contexto de la lista y el @{..} quita la referencia de la matriz.

+3

usted no necesita cualquiera de los paréntesis. –

+1

Debo decir que me gusta este método mejor que el caprino. De hecho, me gusta casi todo mejor que el caprino. – Wick

31

Creo que la forma más clara de describir esto sería evitar la conversión instantánea a escalar. Primero asigne una matriz y luego use esa matriz en contexto escalar. Eso es básicamente lo que el lenguaje =() = va a hacer, pero sin la expresión idiomática (muy poco frecuente):

my $string = "one.two.three.four"; 
my @count = $string =~ /\./g; 
print scalar @count; 
+12

+1 por la forma más directa, el operador de cabra da miedo. –

+1

Sin embargo, los paréntesis alrededor de '@ count' son innecesarios. –

19

También, ver Perlfaq4:

Hay un número de maneras, con diferentes eficiencia. Si quieres un recuento de un solo carácter determinado (X) dentro de una cadena, puede utilizar la función tr /// así:

$string = "ThisXlineXhasXsomeXx'sXinXit"; 
$count = ($string =~ tr/X//); 
print "There are $count X characters in the string"; 

Esto está bien si estás en busca de un solo carácter. Sin embargo, si intenta contar varias subcadenas de caracteres dentro de una cadena más grande, tr /// no funcionará. Lo que puede hacer es enrollar un ciclo while() alrededor de una coincidencia de patrón global. Por ejemplo, vamos a contar números enteros negativos:

$string = "-9 55 48 -2 23 -76 4 14 -44"; 
while ($string =~ /-\d+/g) { $count++ } 
print "There are $count negative numbers in the string"; 

Otra versión utiliza un partido global en el contexto de lista, a continuación, asigna el resultado a un escalar, produciendo un recuento del número de coincidencias.

$count =() = $string =~ /-\d+/g; 
1

otra manera,

my $string = "one.two.three.four"; 
@s = split /\./,$string; 
print scalar @s - 1; 
7

es el código después de una sola línea?

print $string =~ s/\./\./g; 
+0

Bueno. ¡Gracias! – Geo

0

El método de Friedo es: $a =() = $b =~ $c.

Pero es posible simplificar aún más esta a solo ($a) = $b =~ $c, así:

my ($matchcount) = $text =~ s/$findregex/ /gi; 
+0

Excepto que esto es una sustitución, no una coincidencia: destruirá la cadena original. Y es la misma idea que @Mike tenía 6 años antes. – fishinear

Cuestiones relacionadas