2015-08-29 35 views
6

pracuję nad Android grze słownej z dużym słowniku -„Szeroki znak w wejściu podprogramu” - kodowanie UTF-8 cyrylicy słowa jako sekwencji bajtów

app screenshot

słów (ponad 700 000) są przechowywane jako oddzielne wiersze w pliku tekstowym (a następnie wstawiane do bazy danych SQLite)

Aby uniemożliwić konkurentom wydobycie mojego słownika, chciałbym zakodować wszystkie słowa dłuższe niż 3 znaki z md5. nie zamazyj krótkich słów i słów rzadkimi rosyjskimi literami ъ i э, ponieważ chciałbym wymienić je w mojej aplikacji).

Więc tutaj jest mój skrypt, który próbuję uruchomić z Perl v5.18.2 na 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 
} 

Jak widać, muszę używać cyrylicy w kodzie źródłowym mojej Perl skrypt - dlatego umieściłem na jego szczycie use utf8;.

Jednak moim prawdziwym problemem jest to, że length($_) zgłasza zbyt wysokie wartości (prawdopodobnie podając liczbę bajtów zamiast liczby znaków).

Więc próbowałem dodając:

binmode(STDOUT, ":raw"); 

lub:

binmode(STDOUT, ":utf8"); 

Ale skrypt następnie umiera z szeroki znak w wejściu podprogramu w zgodzie z print md5_hex($_).

Pomóż mi poprawić scenariusz.

go uruchomić jak:

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

i tutaj jest przykładem words.txt dane dla wygody:

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

Odpowiedz

9

md5_hex oczekuje ciąg bajtów na wejściu, ale jesteś przekazywanie rozszyfrowanego ciągu znaków (ciąg znaków kodu Unicode). Jawnie koduj ciąg znaków.

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

Dzięki 'md5_hex()' rzeczywiście powodując awarię. Przeoczyłem tę część w [perldoc Digest :: MD5] (http://search.cpan.org/dist/Digest-MD5/MD5.pm) –

+1

Idealnie! Miałem podobny problem z konwertowaniem bazowej 64 cyrylicy (i innych) liter, innych niż łaciński. Właśnie dodałem to i działa jak urok! Dziękujemy i @AlexanderFarber! – Arsenii

2

moim prawdziwym problemem jest to, że długość ($ _) informuje, zbyt wysokie wartości

Tak, czytasz z uchwytu ARGV plików i nie ustawić jego kodowanie UTF-8

Możesz użyć pragma open, aby to naprawić.Zamiast wszystkich sprawozdań binmode użyć

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

który będzie zmienić domyślny tryb otwarty dla wszystkich uchwytów plików, włącznie z tymi standardowymi, aby :encoding(utf8)