2015-08-29 24 views
6

Sto lavorando su un gioco di parole Android con un grande dizionario -'carattere esteso in ingresso subroutine" - codifica UTF-8 parole in cirillico come sequenza di byte

app screenshot

Le parole (più di 700 000) vengono mantenute come righe separate in un file di testo (e quindi inserite in un database SQLite)

Per impedire ai concorrenti di estrarre il mio dizionario, mi piacerebbe codificare tutte le parole che sono più lunghe di 3 caratteri con MD5. non offuscare parole e parole brevi con rare lettere russe ъ e э, perché mi piacerebbe elencare loro nella mia app).

Così qui è il mio script, che cerco di correre con perl v5.18.2 su Mac Yosemite:

#!/usr/bin/perl -w 

use strict; 
use utf8; 
use Digest::MD5 qw(md5_hex); 

binmode(STDIN, ":utf8"); 
#binmode(STDOUT, ":raw"); 
binmode(STDOUT, ":utf8"); 

while(<>) { 
     chomp; 
     next if length($_) < 2; # ignore 1 letter junk 
     next if /жы/;   # impossible combination in Russian 
     next if /шы/;   # impossible combination in Russian 

     s/ё/е/g; 

     #print "ORIGINAL WORD $_\tENCODED WORD: "; 

     if (length($_) <= 3 || /ъ/ || /э/) { # do not obfuscate short words 
       print "$_\n";    # and words with rare letters 
       next; 
     } 

     print md5_hex($_) . "\n";   # this line crashes 
} 

Come potete vedere, devo usare cirillico nel codice sorgente della mia Perl script - è per questo che ho messo use utf8; in cima.

Tuttavia il mio vero problema è che length($_) riporta valori troppo alti (probabilmente riportando il numero di byte anziché il numero di caratteri).

Così ho provato ad aggiungere:

binmode(STDOUT, ":raw"); 

o:

binmode(STDOUT, ":utf8"); 

Ma lo script muore poi con largo personaggio in ingresso subroutine alla linea con print md5_hex($_).

Please help me per fissare il mio script.

corro come:

perl ./generate-md5.pl <words.txt> encoded.txt 

e qui è esempio words.txt dati per la vostra convenienza:

а 
аб 
абв 
абвг 
абвгд 
съемка 

risposta

9

md5_hex si aspetta una stringa di byte per l'ingresso, ma sei passando una stringa decodificata (una stringa di punti codice Unicode). Codifica esplicitamente la stringa.

use strict; 
use utf8; 
use Digest::MD5; 
use Encode; 
... 
# $_ is assumed to be utf8 encoded without check 
print Digest::MD5::md5_hex(Encode::encode_utf8($_)),"\n"; 
# Conversion only when required: 
print Digest::MD5::md5_hex(utf8::is_utf8($_) ? Encode::encode_utf8($_) : $_),"\n"; 
+0

Grazie 'md5_hex()' è stato effettivamente causando l'incidente. Ho trascurato quella parte in [perldoc Digest :: MD5] (http://search.cpan.org/dist/Digest-MD5/MD5.pm) –

+1

Perfetto! Ho avuto un problema simile con la conversione in base64 di lettere cirilliche (e di altro tipo) diverse dal latino. L'ho appena aggiunto e funziona come un incantesimo! Grazie a @AlexanderFarber! – Arsenii

2

il mio vero problema è che la lunghezza ($ _) riporta valori troppo alti

Sì, si sta leggendo dal manico ARGV di file e non è stato impostato la sua codifica UTF-8

È possibile utilizzare il pragma open per risolvere questo problema.Invece di tutti i tuoi binmode dichiarazioni, utilizzare

use open qw/ :std :encoding(utf8) /; 

che cambierà la modalità di apertura predefinito per tutti i filehandle, compresi quelli standard, per :encoding(utf8)

Problemi correlati