2012-04-24 2 views
3

J'utilise SimpleDB pour mon application. Tout se passe bien sauf si la limitation d'un attribut est de 1024 octets. Donc, pour une longue chaîne, je dois hacher la chaîne en morceaux et la sauvegarder. Mon problème est que parfois ma chaîne contient un caractère Unicode (chinois, japonais, grec) et la fonction substr() est basée sur le nombre de caractères et non sur octet.Perl substr basé sur des octets

J'ai essayé d'utiliser use bytes pour la sémantique des octets ou plus tard substr(encode_utf8($str), $start, $length) mais cela n'aide pas du tout.

Toute aide serait appréciée.

+0

Quelle version de Perl utilisez-vous? – Rahul

+0

ma version perl est v5.12.3 –

Répondre

5

UTF-8 a été conçu de sorte que les limites de caractères sont faciles à détecter. Pour diviser la chaîne en morceaux de UTF-8 valide, vous pouvez simplement utiliser les éléments suivants:

my $utf8 = encode_utf8($text); 
my @utf8_chunks = $utf8 =~ /\G(.{1,1024})(?![\x80-\xBF])/sg; 

Ensuite, soit

# The saving code expects bytes. 
store($_) for @utf8_chunks; 

ou

# The saving code expects decoded text. 
store(decode_utf8($_)) for @utf8_chunks; 

Démonstration:

$ perl -e' 
    use Encode qw(encode_utf8); 

    # This character encodes to three bytes using UTF-8. 
    my $text = "\N{U+2660}" x 342; 

    my $utf8 = encode_utf8($text); 
    my @utf8_chunks = $utf8 =~ /\G(.{1,1024})(?![\x80-\xBF])/sg; 

    CORE::say(length($_)) for @utf8_chunks; 
' 
1023 
3 
+0

Le métacaractère '\ G' de votre regex est sûrement suplémentaire? – Borodin

+0

+1 - très intelligent – mob

+0

@Borodin, Oui et non. Cela ne ferait aucune différence pour le moteur regex, mais cela ferait une différence pour le lecteur. Nous voulons faire correspondre où le match précédent s'est arrêté, alors ne cachons pas cela. – ikegami

1

substr fonctionne sur les caractères de 1 octet à moins que la chaîne n'ait l'indicateur UTF-8. Donc, cela vous donnera les 1024 premiers octets d'une chaîne décodée:

substr encode_utf8($str), 0, 1024;

bien, pas nécessairement diviser la chaîne sur limites de caractères. Pour supprimer tous les caractères fendus à la fin, vous pouvez utiliser:

$str = decode_utf8($str, Encode::FB_QUIET); 
+1

Cela ne divise pas nécessairement la chaîne sur les limites de caractères, donc l'OP ne pouvait pas appeler 'decode_utf8' sur un morceau individuel (ce qui pourrait être OK). – mob

+0

Incorrect; substr fonctionne sur les caractères (quelle que soit leur taille en octets), pas sur les octets. – felwithe

+0

@mob: ils pourraient passer Encode :: FB_QUIET' comme deuxième paramètre. –

Questions connexes