2010-09-28 10 views
12

Tengo el siguiente script en Perl contando el número de Fs y Ts en una cadena:¿Cómo puedo contar personajes en Perl?

my $str = "GGGFFEEIIEETTGGG"; 
my $ft_count = 0; 
$ft_count++ while($str =~ m/[FT]/g); 
print "$ft_count\n"; 

¿Existe una manera más concisa para obtener el recuento (en otras palabras, para combinar la línea 2 y 3)?

Respuesta

24
my $ft_count = $str =~ tr/FT//; 

Ver perlop.

Si la LISTA DE REEMPLAZO está vacía, se replica la LISTA DE BÚSQUEDA . Este último es útil para contar caracteres en una clase & hellip;

$cnt = $sky =~ tr/*/*/;  # count the stars in $sky 
    $cnt = tr/0-9//;   # count the digits in $_ 

Aquí es un punto de referencia:

use strict; use warnings; 

use Benchmark qw(cmpthese); 

my ($x, $y) = ("GGGFFEEIIEETTGGG" x 1000) x 2; 

cmpthese -5, { 
    'tr' => sub { 
     my $cnt = $x =~ tr/FT//; 
    }, 
    'm' => sub { 
     my $cnt =()= $y =~ m/[FT]/g; 
    }, 
}; 
  Rate  tr  m 
    Rate  m tr 
m 108/s -- -99% 
tr 8118/s 7440% --

Con ActiveState Perl en 5.10.1.1006 32 Windows XP.

La diferencia parece ser más marcado con

C:\Temp> c:\opt\strawberry-5.12.1\perl\bin\perl.exe t.pl 
     Rate  m  tr 
m 88.8/s  -- -100% 
tr 25507/s 28631%  --
+0

esto debería ser 'my $ ft_count = $ str = ~ tr/FT/FT /;', de lo contrario eliminará los caracteres de '$ str' – Hasturkun

+0

bien, lo omití. aún así puedes quitar los corchetes. – Hasturkun

+0

Cuenta los corchetes. Debe ser 'tr/FT //' – Toto

8

sí, se puede utilizar el CountOf secret operator:

my $ft_count =()= $str =~ m/[FT]/g; 
+2

También conocido como el operador de cabras;) '=() =' – Daenyth

+0

oh dios por qué .... tyvm Daenyth ......: O todo esto para decir que los informadores están realmente locos – Sosi

0

Puede combinar la línea 2, 3 y 4 en un solo modo:

my $str = "GGGFFEEIIEETTGGG"; 
print $str =~ s/[FT]//g; #Output 4; 
+2

Siendo un comentario en otra respuesta, esto sería mejor como un comentario que como una respuesta :) – ysth

+0

@ ysh, gracias por el comentario. No me di cuenta de que mi respuesta es en realidad un comentario sobre otra respuesta, ¿o sí? El OP pregunta [¿Hay una forma más concisa para obtener el conteo (en otras palabras, para combinar la línea 2 y 3) y aquí está mi respuesta a la pregunta. ¿Alguien ya había mencionado lo que sugerí? – Mike

+0

@ysth, la publicación original es un posible duplicado de esto [http://stackoverflow.com/questions/1849329/is-there-a-perl-shortcut-to-count-the-number-of-matches-in- a-string/1850686 # 1850686] y publiqué una solución similar a esa pregunta. Creo que esta publicación se puede combinar con esa. – Mike

8

Cuando el operador "m" tiene el indicador/g Y se ejecuta en contexto de lista, devuelve una lista o f subcadenas coincidentes. Así que otra forma de hacerlo sería:

my @ft_matches = $str =~ m/[FT]/g; 
my $ft_count = @ft_matches; # count elements of array 

Pero eso sigue siendo dos líneas. Otro truco más raro que puede hacer que sea más corto:

my $ft_count =() = $str =~ m/[FT]/g; 

El "() =" Las fuerzas de la "m" para estar en el contexto de lista. Asignar una lista con N elementos a una lista de cero variables en realidad no hace nada. Pero cuando esta expresión de asignación se utiliza en un contexto escalar ($ ft_count = ...), el operador "=" derecho devuelve la cantidad de elementos de su lado derecho - exactamente lo que desea.

Esto es increíblemente extraño cuando lo encontré por primera vez, pero el modismo "=() =" es un truco útil de Perl para saber, para "evaluar en contexto de lista, luego obtener el tamaño de la lista".

Nota: No tengo datos sobre cuáles de estos son más eficientes cuando se trata de cadenas grandes. De hecho, sospecho que su código original podría ser mejor en ese caso.

Cuestiones relacionadas