2016-04-17 17 views
2

Ich weiß, ich kann vorwärts durchlaufen durch eine Multibyte-String, in C, mit mbrtowc(). Was aber, wenn ich rückwärts iterieren wollte? oder mit anderen Worten, wie finde ich das vorherige gültige Multibyte-Zeichen. Ich habe versucht, die folgende Methode und es zumindest teilweise funktioniert auf meinem Ubuntu-System der Standard-en_US.UTF-8-Locale verwenden:Iterating rückwärts Multibyte String - C

 char *str = "\xc2\xa2\xc2\xa1xyzwxfd\xc2\xa9", *tmp = NULL; 
     wchar_t wc = 0; 
     size_t ret = 0, width = 1; 
     mbstate_t state = {0}; 

     //Iterate through 2 characters using mbrtowc() 
     tmp = str; 
     tmp += mbrtowc(&wc, tmp, MB_CUR_MAX, &state); 
     tmp += mbrtowc(&wc, tmp, MB_CUR_MAX, &state); 

     //This is a simplified version of my code. I didnt test this 
     //exact code but this general idea did work. 
     for(tmp--; (ret = mbrtowc(&wc, tmp, width, &state)) == (size_t)(-1) || ret == (size_t)(-2); width++, tmp--) 
      if(width == MB_CUR_MAX) printf("error\n"); 

     printf("last multibyte character %lc\n", wc); 

Die Idee ist einfach nur durchläuft nach hinten durch ein Byte, bis wir ein gültiges Multibyte-Zeichen finden als definiert durch mbrtowc(). Meine Frage ist, kann ich darauf verlassen, dass dies für jedes mögliche Multibyte-Gebietsschema funktioniert oder nur mit speziellen Eigenschaften kodiert. Genauer gesagt wird mbstate_t falsch verwendet; Ich meine, könnte die Richtungsänderung die Gültigkeit von mbstate_t beeinflussen? Kann ich garantieren, dass "ret" nur (size_t) (- 1) oder (size_t) (- 2) sein wird, weil ich derzeit davon ausgehe, dass "ret" sowohl von den Definitionen für unvollständige als auch von ungültigen Multibyte-Zeichen abhängig sein könnte .

+0

Wenn Sie positiv sind, müssen Sie nur UTF8-Strings verarbeiten, dann: das erste Byte von * any * UTF8-Sequenz ist einzigartig. – usr2564301

+3

Bei Legacy-Doppelbyte-Kodierungen ist es jedoch im Allgemeinen nicht möglich, rückwärts zu iterieren, ohne tatsächlich von Anfang an zu beginnen. –

+0

@RadLexus Danke für den Rat, aber leider kann ich diese Annahme nicht machen. –

Antwort

5

Wenn Sie mit theoretisch möglichen Multibyte-Kodierung umgehen müssen, ist es nicht möglich, rückwärts zu iterieren. Es gibt keine Anforderung, dass eine Multibyte-Codierung die Eigenschaft aufweist, dass kein richtiges Suffix einer gültigen Multibyte-Sequenz eine gültige Multibyte-Sequenz ist. (Wie dem auch sei, Ihr Algorithmus benötigt eine noch stärkere Eigenschaft, weil Sie möglicherweise eine Multibyte-Sequenz in der Mitte einer gültigen Sequenz erkennen und in die nächste Sequenz fortfahren.)

Auch können Sie nicht vorhersagen (wieder, im Allgemeinen) der Multibyte-Zustand, wenn die Multibyte-Codierung Shift-Zustände hat. Wenn Sie eine Multibyte-Sequenz sichern, die den Status ändert, haben Sie keine Ahnung, was der vorherige Zustand war.

UTF-8 wurde in diesem Sinne entwickelt. Es hat keine Shift-Zustände und markiert eindeutig die Oktette (Bytes), die eine Sequenz starten können. Wenn Sie also wissen, dass die Multibyte-Kodierung UTF-8 ist, können Sie leicht rückwärts iterieren. Suchen Sie einfach rückwärts nach einem Zeichen, das nicht im Bereich 0x80-0xBF liegt. (UTF-16 und UTF-32 können auch leicht in beide Richtungen iteriert werden, aber Sie müssen sie als Zwei-/Vier-Byte-Codeeinheiten lesen, da ein falsch ausgerichteter Lesevorgang wahrscheinlich ein korrekter Codepunkt ist.)

Wenn Sie nicht wissen, dass die Multibyte-Codierung UTF-8 ist, dann gibt es einfach keinen robusten Algorithmus, um rückwärts zu iterieren. Sie können nur vorwärts iterieren und sich die Startposition und mbstate jedes Zeichens merken.

Glücklicherweise gibt es heutzutage kaum einen Grund, Multibyte-Kodierungen anders als Unicode-Kodierungen zu unterstützen.

0

Für UTF-8 können Sie die encoding property der zusätzlichen Bytes nach dem ersten nutzen: die zusätzlichen Bytes eines Multibyte-Zeichen (und nur sie) beginnen mit 10xx xxxx.

Also, wenn Sie rückwärts gehen ein Zeichen ist so, dass (c & 0xC0)==0x80 dann können Sie es überspringen.

Für andere Multibyte-Kodierung müssen Sie nicht unbedingt eine so einfache Lösung haben, wie die führenden und folgenden Bytes in ranges that overlap sind.