2009-09-30 4 views
11

Ich bin mir bewusst, dass es verschiedene Fragen über utf-8 gab, hauptsächlich über Bibliotheken, um utf-8 'string' -ähnliche Objekte zu manipulieren.Utf-8 in C++: schnelle & schmutzige Tricks

Ich arbeite jedoch an einem "internationalisierten" Projekt (eine Website, von der ich ein C++ - Backend code ... nicht stelle), wo selbst wenn wir mit utf-8 umgehen, wir solche nicht wirklich brauchen Bibliotheken. In den meisten Fällen sind die einfachen std :: string-Methoden oder STL-Algorithmen sehr ausreichend für unsere Bedürfnisse, und tatsächlich ist dies das Ziel, utf-8 überhaupt zu verwenden.

Also, was ich suche hier eine Kapitalisierung der „Quick-& Dirty“ Tricks, die Sie von verwandten kennen zu utf-8 gespeichert, wie std :: string (keine const char *, das tue ich nicht c-style code wirklich, ich habe bessere Dinge zu tun, als sich ständig Sorgen über meine Puffergröße).

Zum Beispiel, hier ist ein "Schnell & Dirty" Trick, um die Anzahl der Zeichen zu erhalten (was nützlich ist, zu wissen, ob es in Ihrer Display-Box paßt):

#include <string> 
#include <algorithm> 

// Let's remember than in utf-8 encoding, a character may be 
// 1 byte: '0.......' 
// 2 bytes: '110.....' '10......' 
// 3 bytes: '1110....' '10......' '10......' 
// 4 bytes: '11110...' '10......' '10......' '10......' 
// Therefore '10......' is not the beginning of a character ;) 

const unsigned char mask = 0xC0; 
const unsigned char notUtf8Begin = 0x80; 

struct Utf8Begin 
{ 
    bool operator(char c) const { return (c & mask) != notUtf8Begin; } 
}; 

// Let's count 
size_t countUtf8Characters(const std::string& s) 
{ 
    return std::count_if(s.begin(), s.end(), Utf8Begin()); 
} 

In der Tat I haben noch eine usecase zu begegnen, wenn ich irgendetwas anderes als die Anzahl der Zeichen benötigen würde und dass std :: string oder die STL-Algorithmen bieten nicht kostenlos seit:

  • Sortierarbeiten wie
  • erwartet
  • kein Teil eines Wortes kann

verwechseln Ich mag würde wissen, wenn Sie andere vergleichbare Tricks als ein Wort oder einen Teil eines anderen Wortes, und zwar sowohl für das Zählen und für andere einfache Aufgaben.
Ich wiederhole, ich weiß über ICU und Utf8-CPP, aber ich bin nicht daran interessiert, da ich keine vollwertige Behandlung brauche (und in der Tat habe ich nie mehr als die Anzahl der Zeichen benötigt).
Ich wiederhole auch, dass ich nicht daran interessiert bin, char * s zu behandeln, sie sind altmodisch.

+9

Also Diakritika zu kombinieren ist für Sie egal? Das ist traurig. Sie könnten Zeichen nach Ihrer Zählung sein, aber sie brauchen nicht mehr Platz. Irgendein kombinierender Charakter, eigentlich. Oder leere Leerzeichen. Und Sortierung funktioniert wie erwartet? Was erwartest du? Wie würde eine länderspezifische Sortierung über die Sortierung wissen, wenn Sie absichtlich kein Unicode verwenden (außer als eine Art Byte-Array)? – Joey

+0

Siehe meine Bearbeitung, meine Anwendung ist ein Backend für eine Website, daher ist das Gebietsschema in der Hand des Browsers. Wir haben noch nie das Problem der sich kombinierenden Charaktere kennengelernt, ich habe von ihnen gehört, aber nie gesehen, in welchen Sprachen begegnen Sie ihnen? –

+0

Ein paar Anwendungsfälle, die nicht für nicht-englischen Text funktionieren: Sortieren, Falzen, Zusammenpassen (zum Beispiel deutsch ß und ss). –

Antwort

5

Nun, dieser schmutzige Trick wird nicht funktionieren. Erstens, was der Wert der Maske danach ist:

const unsigned char mask = 0x11000000; 
    const unsigned char notUtf8Begin = 0x10000000; 

Vielleicht Darstellung Sie mischen hex mit binär.

Zweitens, wie Sie richtig in utf-8 Codierung sagen, ein Zeichen kann mehrere Bytes lang sein. std :: count_if durchläuft alle Bytes in einer UTF8-Sequenz. Aber was Sie tatsächlich brauchen, ist, für jedes Zeichen das führende Byte zu betrachten und den Rest zu überspringen, bis das nächste Zeichen kommt.

Es wird nicht schwierig sein, einen einzigen Zyklus zu implementieren, der die Berechnung und den Sprung vorwärts mit der einfachen Maskentabelle für führende Bytes durchführt.

Am Ende erhalten Sie das gleiche O (n) für die Überprüfung der Zeichen und es wird mit jeder UTF8-Zeichenfolge funktionieren.

+0

Ja, meine Masken sind durcheinander, sorry. Jedoch ist count_if immer noch korrekt, abgesehen von dem diakritischen Kombinationsproblem. –

+0

Ich arbeitete an einer utf8-String-Klasse, wo ++ über breite Codepunkte richtig gehen würde und gab das Offset-Array für den Sprung von Byte zu Byte auf. Es funktioniert gut vorwärts, aber für - es bietet keinen Nutzen. Der pedantische Code ist einfacher zu pflegen. – jmucchiello

1

Das Sortieren von UTF_8 als Binärcode wird nicht in 'Unicode'-Reihenfolge sortiert. BOCU-1 würde. Wie gesagt, Ihr "wie erwartet" ist ein ziemlich niedriger Balken für nicht-englischen Inhalt.

0

Wir behandeln es auch so in OpenLieroX (das ist wirklich gut in einem Spiel denke ich).

Wir haben eine Reihe nützlicher Funktionen/Algorithmen für solche UTF-8 std :: strings. Siehe Unicode.h und Unicode.cpp. Zum Beispiel gibt es UTF8-Iteratoren, einige einfache Manipulationsoperatoren (einfügen oder löschen), Groß-/Kleinschreibungumwandlungen, fallunabhängige Suche, etc.

Aber erwarten Sie nicht, dass diese Funktionen immer korrekt sind. Zum Beispiel wissen sie nicht wirklich über die Kombination von Diakritika oder verschiedene Möglichkeiten, den gleichen Text zu kodieren.