11
votes

Moyen efficace de calculer la longueur d'octet d'un caractère, en fonction du codage

Quel est le moyen le plus efficace de calculer la longueur d'octet d'un caractère, en prenant en compte le caractère de personnage? Le codage ne serait connu que pendant l'exécution. Dans UTF-8, par exemple, les caractères ont une longueur d'octet variable, chaque caractère doit donc être déterminé individuellement. Aussi loin maintenant, je suis arrivé à cela:

char c = getCharSomehow();
String encoding = getEncodingSomehow();
CharsetEncoder encoder = Charset.forName(encoding).newEncoder();
// ...
int length = encoder.encode(CharBuffer.wrap(new char[] { c })).limit();


6 commentaires

En utilisant ce qui précède avez-vous eu des problèmes de performance? Voulez-vous toujours utiliser UTF-8?


L'exemple était en effet un peu trompeur, mais le codage ne peut être déterminé que pendant l'exécution. J'ai mis à jour la question. Après tout, cela n'a pas l'air d'être une tâche facile cependant.


C'est complètement faux et la réponse de Bkkbrad est-elle complètement. C'est en fait assez effrayant de voir autant de gens complètement faux sur celui-là (+1 uniquement à la réponse de Bkail). Un Java Char fait Pas , je répète Un Char Java N'EST PAS N'EST PAS DE PARTICIPE Etant donné Java 1.4 / Unicode 3.1. string.value (char) et envelopper "Char" * et qu'est-ce que toutes méthodes sont toutes des méthodes des années quatre-vingt-dix. Le monde a déménagé et cela a été très long que Unicode a plus de 65 536 codépoints. Utilisez "INT", obtenez "Char" hors de votre esprit car Java Char est brisé au-delà de la réparation. ♩ ♩ ♩


@Wizard: refroidir :) Faites une pause.


J'ai ajouté une nouvelle solution basée sur la critique pointue de Wizard.


Pour toute personne recherchant un moyen de calculer une taille d'octets de chaîne dans UTF-8, vous pouvez utiliser GUAVA'S UTF8.Encodedlength (String)


4 Réponses :


3
votes

Il est possible qu'un schéma d'encodage puisse coder un caractère donné en tant que nombre variable d'octets, en fonction de ce qui vient avant et après la séquence de caractères. La longueur des octets que vous obtenez d'encoder une chaîne de caractères unique n'est donc pas la réponse entière.

(par exemple, vous pouvez recevoir théoriquement un fichier Baudot / TeleType codé sous forme de 4 caractères tous les 3 octets, ou vous pouvez traiter théoriquement un compresseur de flux UTF-16 + comme un schéma de codage. Oui, tout est un peu invraisemblable. , mais ...)


1 commentaires

Oui, bon point, les personnages de substitution doivent en effet être pris en compte tôt ou tard.



3
votes

Si vous pouvez vous garantir que l'entrée est bien formée UTF-8, il n'y a aucune raison de trouver des points de code du tout. L'une des forces de l'UTF-8 est que vous pouvez détecter le début d'un point de code de n'importe quelle position de la chaîne. Il suffit de chercher à l'envers jusqu'à ce que vous trouviez un octet tel que (B & 0XC0)! = 0x80, et vous avez trouvé un autre caractère. Étant donné qu'un point de code codé UTF-8 est toujours de 6 octets ou moins, vous pouvez copier les octets intermédiaires dans un tampon de longueur fixe.

Edit: J'ai oublié de mentionner, même si vous n'allez pas avec cette stratégie, il ne suffit pas d'utiliser une Java "Char" pour stocker des points de code arbitraires car les valeurs de points de code peuvent dépasser 0xFFFF. Vous devez stocker des points de code dans un "INT".


2 commentaires

Très bon conseil. Malheureusement, il n'y a probablement pas de garantie à 100%.


@bkail: +1 Pour vous pour vous, vous êtes le seul dans ce fil de mentionner qu'un Java Char ne peut pas stocker de points de codes arbitraires et que int doit être utilisé à la place.



1
votes

Essayez charset.forname ("utf-8"). Encodé ("chaîne"). Limite (); peut être un peu plus efficace, peut-être pas.


1 commentaires

Cela nécessite encore un String en entrée.



10
votes

Utilisez un Charsetencoder et réutilisez un Charbuffer comme entrée et a bytebuffer comme sortie.

sur mon système, Le code suivant prend 25 secondes pour coder 100 000 caractères simples: xxx

Cependant, le code suivant fait la même chose en moins de 4 secondes: xxx < / pré>

EDIT: Pourquoi les ennemis doivent-ils détester?

Voici une solution qui se lit à partir d'un charbouilleur et garde une trace de paires de substitution : xxx


3 commentaires

Techniquement, c'est la meilleure réponse aussi loin (si vous remplacez position () par limite () ). C'est bien très efficace.


@Bkkbrad: Un Java Char est totalement inadéquat depuis 1993 ou de manière à représenter un caractère Unicode, lorsque Unicode a déménagé à 1,1 et avait plus de 65 536 codépoints. La méthode à utiliser pour obtenir un personnage dans Java est la chaîne codepointat (..) qui retourne correctement un int . Java Char est, bien, complètement brisé. (200 kloc codeBase ici et nous utilisons Java Char, eh bien ... zéro fois).


@WizardOfodds: J'ai ajouté une solution pour garder une trace des paires de substitution.