arrays - ¿Hay un atajo de Perl para contar el número de coincidencias en una cadena?
regex perl4 (8)
¿El siguiente código es de una sola línea?
print $string =~ s//.//./g;
Supongamos que tengo:
my $string = "one.two.three.four";
¿Cómo debería jugar con el contexto para obtener la cantidad de veces que el patrón encontró una coincidencia (3)? ¿Se puede hacer esto usando un trazador de líneas único?
Intenté esto:
my ($number) = scalar($string=~//./gi);
Pensé que al poner paréntesis alrededor de $number
, forzaría el contexto del arreglo, y con el uso de scalar
, obtendría el conteo. Sin embargo, todo lo que obtengo es 1
.
Además, vea Perlfaq4 :
Hay varias formas, con eficiencia variable. Si desea contar un determinado carácter (X) dentro de una cadena, puede usar la función tr /// de la siguiente manera:
$string = "ThisXlineXhasXsomeXx''sXinXit"; $count = ($string =~ tr/X//); print "There are $count X characters in the string";
Esto está bien si solo buscas un solo personaje. 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 usa una coincidencia global en el contexto de la lista, luego asigna el resultado a un escalar, produciendo un recuento de la cantidad de coincidencias.
$count = () = $string =~ /-/d+/g;
Creo que la forma más clara de describir esto sería evitar el lanzamiento instantáneo a escalar. Primero asigne una matriz y luego use esa matriz en contexto escalar. Eso es básicamente lo que hará la expresión = () =
, pero sin la expresión (raramente utilizada):
my $string = "one.two.three.four";
my @count = $string =~ //./g;
print scalar @count;
El método de Friedo es: $a = () = $b =~ $c
.
Pero es posible simplificar esto aún más a solo ($a) = $b =~ $c
, de esta manera:
my ($matchcount) = $text =~ s/$findregex/ /gi;
Podrías agradecer simplemente por envolver esto en una función, getMatchCount()
, y no preocuparte porque destruya la cadena pasada.
Por otro lado, puede agregar un intercambio, que puede ser un poco más de cálculo, pero no da como resultado la alteración de la cadena.
my ($matchcount) = $text =~ s/($findregex)/$1/gi;
Eso pone la expresión regular en contexto escalar, que no es lo que quieres. En su lugar, coloque la expresión regular en el contexto de la lista (para obtener el número de coincidencias) y colóquela en contexto escalar.
my $number = () = $string =~ //./gi;
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 @{..}
elimina la referencia de la matriz.
de otra manera,
my $string = "one.two.three.four";
@s = split //./,$string;
print scalar @s - 1;
my $count = 0;
my $pos = -1;
while (($pos = index($string, $match, $pos+1)) > -1) {
$count++;
}
verificado con Benchmark, es bastante rápido