2016-08-08 53 views
1

ich einen QString in seine hexadezimale Darstellung konvertieren werde, alles funktioniert gut, bis ich einige Sonderzeichen wie ‚€‘ setzen:QString zu utf16 hexadezimale Darstellung für nicht ASCII-Zeichen konvertieren

QString l_str = "How are you"; 
qDebug() << "hex:  " << l_str.toUtf8().toHex(); 
qDebug() << "readable:" << l_str.toUtf8(); 

druckt:

hex: "486f772061726520796f753f"

lesbar: "Wie geht es dir?"

Und es so einfach, die Hex-Werte in ASCII umzuwandeln zurück, wobei nur zwei Werte (48 = H etc.) die hexadezimale Darstellung eines ASCII-Zeichen es genügt, alle zwei Zeichen iterieren und zu konvertieren.

Wenn ich gesetzt l_str = "H € w ar € Sie?", Und das Hex € Zeichen in UTF-8 ist "e282ac", die 6-Werte sind, ist das Ergebnis, wie folgend:

hex: " 48 e282ac 77206172e282ac20796f753f“

aber wie kann ich es zurück in eine lesbare Zeichenfolge?

Es wäre besser, eine Umwandlung, die in einem utf16 String ergibt:

hex: "0048006F20AC00200061007220AC00200079006F0075003F"

Bedenken Sie, dass die "Ho € ar € Sie" string zur Laufzeit erstellt wird (also kein QStringLiteral verfügbar), und ich kann das Auto Schlüsselwort nicht verwenden.

+0

Was meinst du mit "bekomme es zurück zu einer lesbaren Zeichenfolge" genau?Wie liest du die Zeichenfolge? – peppe

+0

Ich lese "ho € ar € you" von einem Webserver, dann muss ich es in utf16 hex Array konvertieren, sende es an ein Gerät, wo ich es wieder in "ho € ar € you" umwandeln muss. – Giancarlo

+0

Und welcher dieser Schritte schlägt fehl? – peppe

Antwort

2

Sie können die Zeichenfolge in utf8/16 konvertieren und dann den Puffer, der diese enthält, in hexadezimale Darstellung konvertieren. Diese Schritte können in umgekehrter Reihenfolge ausgeführt werden, um von hex zu utf8/16 zu einer Zeichenfolge zu wechseln.

Die Funktion toUtf16Hex fügt eine Bytereihenfolge hinzu, so dass sowohl Little- als auch Big-Endian-Hosts die Utf16-Darstellung korrekt decodieren können.

// https://github.com/KubaO/stackoverflown/tree/master/questions/str-to-utf-38831190 
#include <QtCore> 

QByteArray toUtf8Hex(const QString & str) { 
    return str.toUtf8().toHex(); 
} 
QString fromUtf8Hex(const QByteArray & hex) { 
    return QString::fromUtf8(QByteArray::fromHex(hex)); 
} 

QByteArray toUtf16Hex(QString str) { 
    str.prepend(QChar::ByteOrderMark); 
    // It is OK to use `fromRawData` since toHex copies it. 
    return QByteArray::fromRawData(
      reinterpret_cast<const char*>(str.constData()), (str.size()+1)*2).toHex(); 
} 
QString fromUtf16Hex(const QByteArray & hex) { 
    const QByteArray utf16 = QByteArray::fromHex(hex); 
    return QString::fromUtf16(reinterpret_cast<const quint16*>(utf16.data())); 
} 

int main() { 
    const QString str = QStringLiteral("H€w ar€ you?"); 

    // To Utf8 and back 
    const QByteArray hex8 = toUtf8Hex(str); 
    Q_ASSERT(fromUtf8Hex(hex8) == str); 

    // To Utf16 and back 
    const QByteArray hex16 = toUtf16Hex(str); 
    Q_ASSERT(fromUtf16Hex(hex16) == str); 
} 
0

fand ich eine hackish aber funktionierende Lösung:

QString l_str = "Ho€ Ar€ you?"; 
qDebug() << "hex:  " << l_str.toUtf8().toHex(); 
qDebug() << "readable:" << l_str.toUtf8(); 

QTextCodec* l_codec = QTextCodec::codecForName("UTF-16"); 

QByteArray l_string = l_codec->fromUnicode(l_str).toHex(); 
qDebug() << "utf16 encoded: " << l_string; 

QByteArray l_reversed; 

for(int i=0; i < l_string.length(); i=i+4) 
{ 
    QString l_hex_chars_1 = l_string.mid(i, 2); 
    QString l_hex_chars_2 = l_string.mid(i+2, 2); 
    l_reversed.append(l_hex_chars_2); 
    l_reversed.append(l_hex_chars_1); 
} 

QByteArray l_bom("feff"); 
if(l_reversed.startsWith(l_bom)) 
{ 
    l_reversed.remove(0, l_bom.length()); 
} 

QString l_res; 

for(int i=0; i < l_reversed.length(); i=i+4) 
{ 
    QString l_hex_chars_1 = l_reversed.mid(i, 2); 
    QString l_hex_chars_2 = l_reversed.mid(i+2, 2); 

    int l_val = l_hex_chars_1.toInt(0,16)*256+l_hex_chars_2.toInt(0,16); 
    QChar l_char(l_val); 
    l_res.append(l_char); 
} 
qDebug() << "back to string: " << l_res; 

Dies gibt:

hex: "48e282ac77206172e282ac20796f753f"

lesbar: „H € w ar € Sie "

utf16 codiert: "fffe4800ac207700200061007200ac20200079006f0075003f00"

Byte-umgekehrt: "004820ac007700200061007220ac00200079006f0075003f"

zurück zu String: "H € w ar € Sie"

+0

Die utf16 Byte Order Mark ist da, damit der Decoder bei Bedarf Byte-Swapping durchführen kann. Sie sollen nichts selbst tauschen. Sie müssen auch keinen Codec erstellen, um eine utf-16-Repräsentation eines Strings zu erhalten: Sie erhalten einen mit 'QString :: utf16()'. Sie können eine 'QChar :: ByteOrderMark' manuell voranstellen. –