Trabajar con cadenas de bits para hacer operaciones binarias con ellas, siempre ha sido un dolor de cabeza con Perl. Al menos hasta la versión 5.22.
Pero antes, un error sintáctico que he visto en el código (recuerda que con perl -c <programa.pl> el intérprete te avisa de estos errores): en la línea 18 la sentencia acaba con un '.' delante del ';' final. Ese punto sobra. O le falta algo después.
En la documentación de Perl, en el documento perlop, sección "
Operadores de bit en cadenas" (en español), se comenta esta problemática sobre las cadenas de bits. Casi siempre, acababas yendo carácter por carácter para estar seguro.
En el foro de Bioinformática hay un ejemplo muy bonito de esta técnica, para
buscar diferencias en proteínas (líneas 295 a 307).
Bueno, el caso es que hay que tener mucho cuidado con la notación. La siguiente solución me funciona en un Perl v5.18:
Using perl Syntax Highlighting
#!/usr/bin/perl
use v5.18;
my $slacknick = '@Nuiter, ';
my $twit_handle = '@Nuiter_Qur, ';
print "[$slacknick][$twit_handle] HD:", hd($slacknick, $twit_handle), "\n";
sub hd {
my($x, $y) = @_;
my $xor = "$x" ^ "$y";
my $l = length $xor;
my $coincidencias = $xor =~ tr[\0][\0];
my $res = $l - $coincidencias;
say "XOR: [$xor], longitud: ", $l;
say "Coincidencias: $coincidencias";
say "HD: $res";
$res;
}
Coloreado en 0.002 segundos, usando
GeSHi 1.0.8.4
La salida es:
Using text Syntax Highlighting
XOR: [ squr, ], longitud: 13
Coincidencias: 7
HD: 6
[@Nuiter, ][@Nuiter_Qur, ] HD:6
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
He dividido la ejecución en pasos, para detallarlos mejor.
En la línea 11 hacemos la operación Or-exclusivo, pero con los operandos entrecomillados dobles, como recomienda la documentación, para asegurarnos que se hace la operación entre cadenas de caracteres, y no haciendo la conversión a números, en caso de que alguno de los operandos lo sea.
En la línea 12 viene algo importante: lo que nos interesa es calcular el número de diferencias entre las dos cadenas, y eso se consigue sabiendo la longitud de la cadena más larga, menos el número de caracteres coincidentes en la misma posición. Podemos aprovechar el hecho de que la operación de Or-Exclusivo "rellena" con "\0" la cadena más corta, devolviendo una cadena de resultado tan larga como el más largo de los operandos. En el código anterior usabas la longitud del primer argumento, pero daba la casualidad de que era el más corto de los dos, así que la operación de cálculo de diferencias no daba el resultado correcto.
El resto de líneas hace las mismas operaciones que en tu código (longitud de la cadena, menos el número de $coincidencias).
En el resultado, en la terminal no vemos lo que hay delante de "squr, ", porque son bytes "\0", pero se pueden ver con un volcador hexadecimal, como por ejemplo
hexdump -C:
Using text Syntax Highlighting
explorer@Arcanus:~/Documentos/Desarrollo > perl code_41484.pl |hexdump -C
00000000 58 4f 52 3a 20 5b 00 00 00 00 00 00 00 73 71 75 |XOR: [.......squ|
00000010 72 2c 20 5d 2c 20 6c 6f 6e 67 69 74 75 64 3a 20 |r, ], longitud: |
00000020 31 33 0a 43 6f 69 6e 63 69 64 65 6e 63 69 61 73 |13.Coincidencias|
00000030 3a 20 37 0a 48 44 3a 20 36 0a 5b 40 4e 75 69 74 |: 7.HD: 6.[@Nuit|
00000040 65 72 2c 20 5d 5b 40 4e 75 69 74 65 72 5f 51 75 |er, ][@Nuiter_Qu|
00000050 72 2c 20 5d 20 48 44 3a 36 0a |r, ] HD:6.|
0000005a
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
Ahí ves los byte "\0".
Por fortuna, como hemos dicho antes, Perl ha evolucionado y ya hay
un mejor soporte para estas operaciones. A partir de Perl v5.22 hay un soporte experimental para la característica "
bitwise" que añade operadores específicos para cadenas de bits. A partir de Perl v5.28 ya forma parte del lenguaje.
Entonces, el código queda un poco más ligero:
Using perl Syntax Highlighting
#!/usr/bin/env perl
use v5.28;
use experimental 'signatures';
my $slacknick = '@Nuiter, ';
my $twit_handle = '@Nuiter_Qur, ';
say "[$slacknick][$twit_handle] HD:", hd($slacknick, $twit_handle);
sub hd ($x, $y) {
my $xor = $x ^. $y;
length($xor) - $xor =~ tr[\0][\0];
}
Coloreado en 0.001 segundos, usando
GeSHi 1.0.8.4
La salida es:
Using text Syntax Highlighting
[@Nuiter, ][@Nuiter_Qur, ] HD:6
Coloreado en 0.000 segundos, usando
GeSHi 1.0.8.4
Hemos añadido la característica (aún) experimental 'signatures' para acceder a los argumentos de la función, y en la operación de Or-exclusivo hemos usado el nuevo operador "^." para obligar a que la operación sea en cadenas de caracteres.
(Para el que no acabe de entender por qué sale un 6, es porque las cadenas difieren a partir de la "," en la octava posición -los primeros 7 caracteres son iguales-. La cadena más larga tiene 13 caracteres, así que la diferencia es 6).