904 Stimmen

std::wstring VS std::string

Ich bin nicht in der Lage, die Unterschiede zu verstehen zwischen std::string y std::wstring . Ich weiß wstring unterstützt breite Zeichen wie Unicode-Zeichen. Ich habe die folgenden Fragen:

  1. Wann sollte ich die std::wstring über std::string ?
  2. Dose std::string den gesamten ASCII-Zeichensatz, einschließlich der Sonderzeichen, enthalten?
  3. Ist std::wstring von allen gängigen C++-Compilern unterstützt?
  4. Was genau ist ein " breiter Charakter "?

13 Stimmen

Der ASCII-Zeichensatz enthält nicht viele "Sonderzeichen", das exotischste ist wahrscheinlich ` (Anführungszeichen). std::string kann etwa 0,025% aller Unicode-Zeichen aufnehmen (normalerweise 8-Bit-Zeichen)

1 Stimmen

Wenn Sie mit "Sonderzeichen" die Zeichen von 128 bis 255 meinen, die von der verwendeten Norm abhängen, dann werden sie unterstützt.

4 Stimmen

Gute Informationen über breite Schriftzeichen und den zu verwendenden Typ finden Sie hier: programmers.stackexchange.com/questions/102205/

113voto

Pavel Radzivilovsky Punkte 18418

Ich empfehle, Folgendes zu vermeiden std::wstring unter Windows oder anderswo, es sei denn, dies ist für die Schnittstelle erforderlich, oder in der Nähe von Windows-API-Aufrufen und entsprechenden Kodierungsumwandlungen als syntaktischer Zucker.

Meine Ansicht ist zusammengefasst in http://utf8everywhere.org an dem ich als Mitautor beteiligt bin.

Sofern Ihre Anwendung nicht auf API-Aufrufe ausgerichtet ist, z. B. bei einer UI-Anwendung, empfiehlt es sich, Unicode-Strings in std::string zu speichern und in UTF-8 zu kodieren und die Konvertierung bei API-Aufrufen durchzuführen. Die in diesem Artikel beschriebenen Vorteile überwiegen die offensichtlichen Unannehmlichkeiten der Konvertierung, insbesondere bei komplexen Anwendungen. Dies gilt umso mehr für die Entwicklung von Multiplattformen und Bibliotheken.

Und nun zur Beantwortung Ihrer Fragen:

  1. Ein paar schwache Gründe. Es gibt sie aus historischen Gründen, da man glaubte, dass Widechars der richtige Weg zur Unterstützung von Unicode sind. Es wird jetzt verwendet, um APIs zu verbinden, die UTF-16-Strings bevorzugen. Ich verwende sie nur in der unmittelbaren Umgebung solcher API-Aufrufe.
  2. Dies hat nichts mit std::string zu tun. Es kann jede Kodierung enthalten, die Sie hineinlegen. Die einzige Frage ist, wie Sie seinen Inhalt behandeln. Ich empfehle UTF-8, damit alle Unicode-Zeichen korrekt dargestellt werden können. Unter Linux ist dies eine gängige Praxis, aber ich denke, Windows-Programme sollten dies ebenfalls tun.
  3. Non.
  4. Wide character ist ein verwirrender Name. In den Anfängen von Unicode war man der Meinung, dass ein Zeichen in zwei Bytes kodiert werden kann, daher der Name. Heute steht er für "jeden Teil des Zeichens, der zwei Bytes lang ist". UTF-16 wird als eine Folge solcher Byte-Paare (auch Wide characters genannt) betrachtet. Ein Zeichen in UTF-16 besteht entweder aus einem oder zwei Paaren.

0 Stimmen

Hier ist meine Erklärung der Zeichenkettenkodierungen im Zusammenhang mit JavaScript: github.com/duzun/string-encode.js/blob/master/

0 Stimmen

Ich denke, dass Ihre Idee der Verwendung von wstring nur auf API-Aufrufe interessant ist, aber ich bin ein bisschen verwirrt über Daten erhalten in in das Programm einzufügen; im Moment verwende ich einen Stringstream, in den ich die Daten aus einem fstream leite. Kann man davon ausgehen, dass die C++-Standardbibliothek in der Lage ist, zu erkennen, dass eine Textdatei UTF-8 ist, und dass sie automatisch einen String in der richtigen Kodierung konstruiert? Oder wird sie die Textdatei als 8-Bit-Zeichen interpretieren und einen verstümmelten Text zurückgeben? Sagen die Standards etwas darüber aus?

1 Stimmen

@jrh": Die C++-Standardbibliothek prüft keine Dateitypen und behandelt keine Kodierungen. Wenn Sie eine UTF8-Datei in eine std::string werden Sie mit einer std::string die UTF8 enthält, mit den damit verbundenen Vor- und Nachteilen. Wenn Sie eine UTF8-Datei in eine std::wstring dann landet man auf dem Müll. (Ähnlich verhält es sich mit dem Streaming einer UTF16-Datei in eine std::string produziert Müll, aber std::wstring wäre gültig, zumindest unter Windows)

42voto

Frunsi Punkte 7019

Daher sollte jeder Leser hier nun ein klares Verständnis der Fakten und der Situation haben. Wenn nicht, dann Sie müssen paercebals außerordentlich umfassende Antwort lesen (Übrigens: Danke!).

Meine pragmatische Schlussfolgerung ist schockierend einfach: Das ganze C++ (und STL) "Zeichencodierungs"-Zeug ist im Wesentlichen kaputt und nutzlos. Schieben Sie es auf Microsoft oder nicht, das wird sowieso nicht helfen.

Meine Lösung, die ich nach eingehender Untersuchung, viel Frustration und den daraus resultierenden Erfahrungen gefunden habe, ist die folgende:

  1. akzeptieren, dass Sie für die Kodierung und Konvertierung selbst verantwortlich sind (und Sie werden sehen, dass vieles davon ziemlich trivial ist)

  2. verwenden Sie std::string für alle UTF-8 kodierten Strings (nur ein typedef std::string UTF8String )

  3. akzeptieren, dass ein solches UTF8String-Objekt nur ein dummer, aber billiger Container ist. Greifen Sie niemals direkt auf Zeichen darin zu und/oder manipulieren Sie sie (kein Suchen, Ersetzen und so weiter). Sie könnten, aber Sie wollen wirklich nicht Ihre Zeit damit verschwenden, Textmanipulationsalgorithmen für Multi-Byte-Strings zu schreiben! Auch wenn andere Leute schon solche Dummheiten gemacht haben, tun Sie das nicht! Lassen Sie es sein! (Nun, es gibt Szenarien, in denen es Sinn macht... verwenden Sie einfach die ICU-Bibliothek für diese).

  4. std::wstring für UCS-2-kodierte Zeichenketten verwenden ( typedef std::wstring UCS2String ) - dies ist ein Kompromiss und ein Zugeständnis an das Chaos, das die WIN32-API mit sich brachte). UCS-2 ist für die meisten von uns ausreichend (mehr dazu später...).

  5. UCS2String-Instanzen zu verwenden, wenn ein zeichenweiser Zugriff erforderlich ist (Lesen, Manipulieren usw.). Jede zeichenbasierte Verarbeitung sollte in einer NICHT-Multibyte-Darstellung erfolgen. Das ist einfach, schnell und leicht.

  6. zwei Utility-Funktionen hinzufügen, um zwischen UTF-8 und UCS-2 hin und her zu konvertieren:

    UCS2String ConvertToUCS2( const UTF8String &str );
    UTF8String ConvertToUTF8( const UCS2String &str );

Die Umrechnungen sind einfach, Google sollte hier helfen ...

Das war's. Verwenden Sie UTF8String überall dort, wo der Speicherplatz knapp ist und für alle UTF-8-E/A. Verwenden Sie UCS2String überall dort, wo die Zeichenkette geparst und/oder manipuliert werden muss. Sie können jederzeit zwischen diesen beiden Darstellungen konvertieren.

Alternativen und Verbesserungen

  • Konvertierungen von & in Ein-Byte-Zeichenkodierungen (z.B. ISO-8859-1) können mit Hilfe von einfachen Übersetzungstabellen realisiert werden, z.B. const wchar_t tt_iso88951[256] = {0,1,2,...}; und den entsprechenden Code für die Konvertierung von und nach UCS2.

  • wenn UCS-2 nicht ausreicht, dann wechseln Sie zu UCS-4 ( typedef std::basic_string<uint32_t> UCS2String )

ICU oder andere Unicode-Bibliotheken?

Für Fortgeschrittene.

1 Stimmen

Verdammt, es ist nicht gut zu wissen, dass es keine native Unicode-Unterstützung gibt.

0 Stimmen

@Frunsi, ich bin neugierig zu wissen, ob Sie versucht haben, Glib::ustring und wenn ja, was sind Ihre Gedanken?

0 Stimmen

@CarolineBeltran: Ich kenne Glib, aber ich habe es nie benutzt und werde es wahrscheinlich auch nie benutzen, weil es auf eine ziemlich unspezifische Zielplattform beschränkt ist (unixoide Systeme...). Die Windows-Portierung basiert auf einer externen win2unix-Schicht, und es gibt IMHO überhaupt keine OSX-Kompatibilitäts-Schicht. All diese Dinge führen eindeutig in eine falsche Richtung, zumindest für meinen Code (auf diesem Arch-Level...) ;-) Also, Glib ist keine Option

27voto

  1. Wenn Sie breite Zeichen in Ihrer Zeichenkette speichern möchten. wide hängt von der Implementierung ab. Visual C++ ist standardmäßig auf 16 Bit eingestellt, wenn ich mich richtig erinnere, während GCC je nach Ziel voreingestellt ist. Hier ist es 32 Bit lang. Bitte beachten Sie wchar_t (wide character type) hat nichts mit Unicode zu tun. Es ist lediglich gewährleistet, dass es alle Mitglieder des größten Zeichensatzes speichern kann, den die Implementierung durch ihre Locales unterstützt, und mindestens so lang wie char ist. Sie können speichern. Unicode-Zeichenfolgen fein in std::string unter Verwendung der utf-8 Kodierung zu. Aber es wird die Bedeutung der Unicode-Codepunkte nicht verstehen. Also str.size() gibt nicht die Anzahl der logischen Zeichen in der Zeichenkette an, sondern lediglich die Anzahl der char- oder wchar_t-Elemente, die in dieser Zeichenkette gespeichert sind. Aus diesem Grund haben die Leute vom gtk/glib C++ Wrapper ein Glib::ustring Klasse, die utf-8 verarbeiten kann.

    Wenn Ihr wchar_t ist 32 Bit lang, dann können Sie utf-32 als Unicode-Kodierung, und Sie können die y behandeln Unicode-Strings mit einer festen Kodierung (utf-32 ist eine feste Länge). Das bedeutet, dass die wstring's s.size() Funktion wird dann Rückgabe der richtigen Anzahl von wchar_t-Elementen y logische Zeichen.

  2. Ja, char ist immer mindestens 8 Bit lang, was bedeutet, dass es alle ASCII-Werte speichern kann.

  3. Ja, alle großen Compiler unterstützen dies.

0 Stimmen

Ich bin neugierig auf die Nummer 2. Ich dachte, 7 Bits wären auch technisch gültig? Oder ist es erforderlich, alles über 7-Bit-ASCII-Zeichen hinaus speichern zu können?

1 Stimmen

Ja, Jalf. c89 spezifiziert minimale Bereiche für Basistypen in der Dokumentation von limits.h (für unsigned char ist das 0..255 min), und ein reines Binärsystem für Integer-Typen. es folgt char, unsigned char und signed char haben minimale Bitlängen von 8. c++ erbt diese Regeln.

17 Stimmen

"Das bedeutet, dass die Funktion s.size() von wstring dann die richtige Anzahl von wchar_t-Elementen und logischen Zeichen zurückgibt." Das ist nicht ganz richtig, selbst für Unicode. Es wäre genauer, Codepoint statt "logisches Zeichen" zu sagen, denn selbst in UTF-32 kann ein bestimmtes Zeichen aus mehreren Codepoints bestehen.

8voto

Ich verwende häufig std::string, um utf-8-Zeichen zu speichern, ohne dass es irgendwelche Probleme gibt. Ich empfehle, dies zu tun, wenn Schnittstellen mit APIs, die utf-8 als den nativen String-Typ auch verwenden.

Ich verwende zum Beispiel utf-8, wenn ich meinen Code mit dem Tcl-Interpreter verbinde.

Der größte Nachteil ist, dass die Länge von std::string nicht mehr die Anzahl der Zeichen in der Zeichenkette ist.

1 Stimmen

Juan : Meinst du, dass std::string alle Unicode-Zeichen aufnehmen kann, aber die [ ]

2 Stimmen

(Windows-spezifisch) Die meisten Funktionen erwarten, dass eine Zeichenkette mit Bytes ASCII und 2 Bytes Unicode ist, ältere Versionen MBCS. Das heißt, wenn Sie 8-Bit-Unicode speichern, müssen Sie in 16-Bit-Unicode konvertieren, um eine Standard-Windows-Funktion aufzurufen (es sei denn, Sie verwenden nur den ASCII-Teil).

1 Stimmen

Wie Greg und Joel (zum Thema Software) bereits erwähnt haben, ist es sehr wichtig zu verstehen, wie die Kodierung mit der API funktioniert, mit der Sie arbeiten. Das ständige Hin- und Herwechseln zwischen 8- und 16-Bit-Kodierung auf einem Windows-System ist möglicherweise nicht optimal.

6voto

Leiyi.China Punkte 147

Eine gute Frage! Ich denke DATA ENCODING (manchmal ein CHARSET auch beteiligt) ist ein GEDÄCHTNISAUSDRUCK MECHANISMUS, um Daten in einer Datei zu speichern oder über ein Netzwerk zu übertragen, daher beantworte ich diese Frage wie folgt:

1. Wann sollte ich std::wstring statt std::string verwenden?

Wenn die Programmierplattform oder die API-Funktion eine Einzelbyte-Funktion ist und wir einige Unicode-Daten verarbeiten oder parsen wollen, z. B. aus der Windows'.REG-Datei oder einem 2-Byte-Stream im Netzwerk lesen, sollten wir die Variable std::wstring deklarieren, um sie einfach zu verarbeiten. z.B.: wstring ws=L "a"(6 Oktette Speicher: 0x4E2D 0x56FD 0x0061), wir können ws[0] verwenden, um das Zeichen '' zu erhalten und ws[1], um das Zeichen '' zu erhalten und ws[2], um das Zeichen 'a' zu erhalten, usw.

2. Kann std::string den gesamten ASCII-Zeichensatz enthalten, einschließlich der Sonderzeichen?

Ja. Aber beachten Sie: Amerikanisches ASCII, d.h. jedes 0x00~0xFF-Oktett steht für ein Zeichen, einschließlich druckbarem Text wie "123abc&*_&", und Sie sagten, ein spezielles, das meist als '.' gedruckt wird, um Redakteure oder Terminals nicht zu verwirren. Und einige andere Länder erweitern ihren eigenen "ASCII"-Zeichensatz, z. B. Chinesisch, verwenden 2 Oktette für ein Zeichen.

Wird std::wstring von allen gängigen C++-Compilern unterstützt?

Vielleicht, oder meistens. Ich habe verwendet: VC++6 und GCC 3.3, YES

4. Was genau ist ein "breites Zeichen"?

ein breites Zeichen bedeutet meist, dass 2 oder 4 Oktette verwendet werden, um die Zeichen aller Länder aufzunehmen. 2 Oktett UCS2 ist ein repräsentatives Beispiel, und weiter z.B. Englisch 'a', sein Speicher ist 2 Oktett von 0x0061 (im Gegensatz zu ASCII 'a's Speicher ist 1 Oktett 0x61)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X