Kodowanie znaków

Standardowo QT przechowuje w QStringach znaki kodowane z użyciem UTF-16 co pozwala na użycie praktycznie dowolnego znaku bez żadnych problemów. Niestety często napotykamy pliki, które zawierają dane tekstowe zapisane z pomocą innych kodowań.

Wygodne przetwarzanie danych z użyciem QT jest możliwe dopiero wtedy kiedy przetworzymy tekst zawarty w pliku na UTF16. Żeby rozpocząć ten proces musimy najpierw wczytać dane do tablicy znaków QByteArray a dopiero potem wykorzystać tą tablicę do odbróbki zwartych w niej danych.

Wczytywanie danych z pliku

void openFile()
    QString fileName = QFileDialog::getOpenFileName(this, "Otwieranie");
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }

    numberOfLinesInFile = 0;
    contentOfFileQByteArray = 0;
    while(!file.atEnd()) {
        QByteArray chunk = file.readLine();
        contentOfFileQByteArray += chunk;
        numberOfLinesInFile++;
    }

W ten sposoób otrzymujemy tablicę QByteArray wypełnioną tekstem z pliku i mamy informacje o ilości linii.

Zmiana kodowania z użyciem QTextCodec

QTextCodec jest klasą, która wymusza użycie części bibliotem z QT5 - w pliku projektu należy dodać QT += core5compat żeby móc z niej skorzystać

Klasa ta umożliwia stworzenie subklasy, która pozwoli zaimplementować kodowanie, którego nie dodali twórcy QT. Standardowo dostępne są kodowania, które często się wykorzystuje i mają oznaczenia:

  • UTF-8
  • UTF-16
  • ISO-8859-2
  • CP1250

Konwersji dokonujemy w następujący sposób (zmiana z CP1250 na UTF-8):

void changeEncoding() {
    QString sourceEncoding = "CP1250";
    QTextCodec *codec = QTextCodec::codecForName(sourceEncoding.toUtf8());
    utf8QString = codec->toUnicode(contentOfFileQByteArray);
}

W QString utf8QString otrzymujemy tekst przetworzony z kodowaniem UTF-8.

Własne kodowanie

Dodanie możliwości przetwarzania nietypowego kodowania wymaga stworzenie subklasy dla QTextCodec i zaimplementowania w niej poniższych funkcji:

  • QByteArray name() const;
  • QList aliases() const;
  • int mibEnum() const;
  • QByteArray convertFromUnicode(const QChar input, int number, QTextCodec::ConverterState state) const;
  • QString convertToUnicode(const char chars, int len, QTextCodec::ConverterState state) const;

Poniżej przykładowy nowy konwerter w postaci subklasy dla QTextCodec

: public QTextCodec {
public:
    mzCodec();
    ~mzCodec();

    QByteArray name() const;
    QList<QByteArray> aliases() const;
    int mibEnum() const;
    QByteArray convertFromUnicode(const QChar *input, int number, QTextCodec::ConverterState *state) const;
    QString convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state) const;
};

mzCodec::mzCodec() {
}

mzCodec::~mzCodec() {
}

QByteArray mzCodec::name() const {
    QByteArray name("mz");
    return name;
}

QList<QByteArray> mzCodec::aliases() const {
    QList<QByteArray> aliasy;
    aliasy.append("mz");
    return aliasy;
}

int mzCodec::mibEnum() const {
    return 9998;
}

QByteArray mzCodec::convertFromUnicode(const QChar *input, int number, QTextCodec::ConverterState *state) const {
    return QByteArray("a");
}

QString mzCodec::convertToUnicode(const char *chars, int len, QTextCodec::ConverterState *state) const {
    return QString("b");

To czy nasza klasa została podpięta do QTextCodec i jest dostępna jako konwerter można sprawdzić za pomocą:

    QTextCodec* codec = QTextCodec::codecForName("mz");
    if (codec)
    {
        qDebug() << "found ";
        qDebug() << codec->name() << '\n';
    }

Istotnym jest by wcześniej została utworzona instancja naszego konwertera, ponieważ wowołanie konstruktora powoduje podpięcie konwertera do listy dostępnych w QTextCodec.

Następny wpis