「Qtの基礎 - 文字コード」の版間の差分
(→概要) |
|||
4行目: | 4行目: | ||
例えば、Visual StudioとQtを連携する場合、ソースコードのファイルの文字コードはUTF-8であるため、文字コードの変換が必要となる。<br> | 例えば、Visual StudioとQtを連携する場合、ソースコードのファイルの文字コードはUTF-8であるため、文字コードの変換が必要となる。<br> | ||
(変換しない場合は文字化けする)<br> | (変換しない場合は文字化けする)<br> | ||
<br><br> | |||
== QStringの内部表現 == | |||
QStringの内部表現は、プラットフォームに関係なく常にUTF-16で文字列を保持する。<br> | |||
<br> | |||
* 内部表現 | |||
*: <syntaxhighlight lang="c++"> | |||
QString str = "こんにちは"; // 内部的にはUTF-16として保存される | |||
</syntaxhighlight> | |||
* 確認方法 | |||
*: <syntaxhighlight lang="c++"> | |||
QString str = "こんにちは"; | |||
QByteArray utf16 = str.toUtf16(); // 内部表現のUTF-16を直接取得 | |||
QByteArray utf8 = str.toUtf8(); // UTF-8に変換 | |||
qDebug() << "UTF-16 size:" << utf16.size(); // UTF-16のバイト数 | |||
qDebug() << "UTF-8 size:" << utf8.size(); // UTF-8のバイト数 | |||
</syntaxhighlight> | |||
<br> | |||
* データの流れ | |||
*: <syntaxhighlight lang="c++"> | |||
// 入力 (UTF-8) -> QString (UTF-16) -> 出力 (任意の文字エンコーディング) | |||
QByteArray utf8_input = "こんにちは"; // UTF-8データ | |||
QString str = QString::fromUtf8(utf8_input); // 内部でUTF-16に変換 | |||
QByteArray output = str.toUtf8(); // 必要に応じてUTF-8に変換して出力 | |||
<br> | |||
QStringは常にUTF-16で保持する仕様であるため、UTF-8として保持する場合はQByteArrayを使用する必要がある。<br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>QByteArrayは、文字単位の操作が難しい。</u><br> | |||
<u>また、Unicode正規化等の操作ができない。</u><br> | |||
<br> | |||
<u>QByteArrayは、文字列長の取得が正確でない可能性がある。</u><br> | |||
<br> | |||
QFile::writeメソッドは、QByteArrayまたはconst char*を期待するため、QStringを直接指定する場合はエラーになる。<br> | |||
QStringからの暗黙の型変換は許可されていない。<br> | |||
<br> | |||
QTextStreamを使用する場合は、エンコーディングを明示的に制御できる。<br> | |||
バイナリモードで書き込む場合は、エンコーディングの制御が完全に開発者の責任になる。<br> | |||
<syntaxhighlight lang="c++"> | |||
QFile file("test.txt"); | |||
QString str = "こんにちは"; | |||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { | |||
// 方法 1 : QTextStreamを使用 (推奨) | |||
QTextStream out(&file); | |||
out.setEncoding(QStringConverter::Utf8); // UTF-8を指定 | |||
out << str; | |||
// 方法 2 : 直接バイト列として書き込む | |||
// file.write(str.toUtf8()); | |||
file.close(); | |||
} | |||
</syntaxhighlight> | |||
<br> | |||
選択の基準<br> | |||
* QStringを使用する場合 | |||
*: テキスト処理や文字列操作が必要な場合 | |||
*: Unicode関連の操作が必要な場合 | |||
*: クロスプラットフォームの互換性が必要な場合 | |||
*: アプリケーション内部の処理では、QString (UTF-16) を使用する。 | |||
*: <br> | |||
* QByteArrayを使用する場合 | |||
*: バイナリデータとして扱う場合 | |||
*: エンコーディングを維持したまま保存、あるいは、送信する場合 | |||
*: メモリ使用量を最小限にする場合 | |||
*: 外部とのやり取り (ファイルI/O、ネットワーク通信等) では、必要に応じてQByteArray (UTF-8) を使用する。 | |||
<br><br> | <br><br> | ||
2025年1月6日 (月) 06:40時点における版
概要
Qtでは、標準の文字コードはUTF-16である。
例えば、Visual StudioとQtを連携する場合、ソースコードのファイルの文字コードはUTF-8であるため、文字コードの変換が必要となる。
(変換しない場合は文字化けする)
QStringの内部表現
QStringの内部表現は、プラットフォームに関係なく常にUTF-16で文字列を保持する。
- 内部表現
QString str = "こんにちは"; // 内部的にはUTF-16として保存される
- 確認方法
QString str = "こんにちは"; QByteArray utf16 = str.toUtf16(); // 内部表現のUTF-16を直接取得 QByteArray utf8 = str.toUtf8(); // UTF-8に変換 qDebug() << "UTF-16 size:" << utf16.size(); // UTF-16のバイト数 qDebug() << "UTF-8 size:" << utf8.size(); // UTF-8のバイト数
- データの流れ
// 入力 (UTF-8) -> QString (UTF-16) -> 出力 (任意の文字エンコーディング) QByteArray utf8_input = "こんにちは"; // UTF-8データ QString str = QString::fromUtf8(utf8_input); // 内部でUTF-16に変換 QByteArray output = str.toUtf8(); // 必要に応じてUTF-8に変換して出力 <br> QStringは常にUTF-16で保持する仕様であるため、UTF-8として保持する場合はQByteArrayを使用する必要がある。<br> <br> <u>※注意</u><br> <u>QByteArrayは、文字単位の操作が難しい。</u><br> <u>また、Unicode正規化等の操作ができない。</u><br> <br> <u>QByteArrayは、文字列長の取得が正確でない可能性がある。</u><br> <br> QFile::writeメソッドは、QByteArrayまたはconst char*を期待するため、QStringを直接指定する場合はエラーになる。<br> QStringからの暗黙の型変換は許可されていない。<br> <br> QTextStreamを使用する場合は、エンコーディングを明示的に制御できる。<br> バイナリモードで書き込む場合は、エンコーディングの制御が完全に開発者の責任になる。<br> <syntaxhighlight lang="c++"> QFile file("test.txt"); QString str = "こんにちは"; if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { // 方法 1 : QTextStreamを使用 (推奨) QTextStream out(&file); out.setEncoding(QStringConverter::Utf8); // UTF-8を指定 out << str; // 方法 2 : 直接バイト列として書き込む // file.write(str.toUtf8()); file.close(); }
選択の基準
- QStringを使用する場合
- テキスト処理や文字列操作が必要な場合
- Unicode関連の操作が必要な場合
- クロスプラットフォームの互換性が必要な場合
- アプリケーション内部の処理では、QString (UTF-16) を使用する。
- QByteArrayを使用する場合
- バイナリデータとして扱う場合
- エンコーディングを維持したまま保存、あるいは、送信する場合
- メモリ使用量を最小限にする場合
- 外部とのやり取り (ファイルI/O、ネットワーク通信等) では、必要に応じてQByteArray (UTF-8) を使用する。
QTextCodecクラスについて
Qt 5 / Qt 6の違い
Qt 6では、QTextCodec
クラスの使用方法が変更された。
Qt 6ではQTextCodec
クラスのインクルードはサポートされておらず、代わりに文字エンコーディングの処理がQStringConverter
クラスに移行された。
これにより、より柔軟で効率的な文字列変換が可能になった。
- Qt 6の場合
#include <QStringConverter>
例えば、Qt 5において、以下に示すようなコードがあるとする。
// Qt 5の場合
#include <QTextCodec>
// Shift-JISからUTF-8へデコードする場合
QByteArray SJISdata = "あいうえお";
QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
QString str = codec->toUnicode(SJISdata);
// UTF-8からShift-JISへエンコードする場合
QString str = "あいうえお";
QByteArray data = str.toUtf8(); // 文字列をバイト列へ変換
QTextCodec *codec; // エンコードオブジェクト
codec = QTextCodec::codecForName("Shift-JIS");
encodedPostData = codec->fromUnicode(data);
Qt 6では、以下に示すように書き換えることができる。
// Qt 6の場合
#include <QStringConverter>
// Shift-JISからUTF-8へデコードする場合
QByteArray SJISdata = "あいうえお";
QStringDecoder decoder("Shift-JIS");
QString str = decoder(SJISdata);
// UTF-8からShift-JISへエンコードする場合
QString str = "あいうえお";
QByteArray data = str.toUtf8(); // 文字列をバイト列へ変換
QStringEncoder encoder("Shift-JIS");
QString encodeStr = encoder(data);
この変更は、QtのコアAPIをより現代的で効率的なものにするための一環である。
新しいAPIは、以前のものと比較してより柔軟性が高く、パフォーマンスも向上している。
Qt 6でQTextCodecクラスを使用する場合
Qt 6において、以前のQTextCodec
クラスを使用することもできる。
- CMakeを使用する場合
find_package(Qt6 REQUIRED COMPONENTS Core5Compat)
target_link_libraries(mytarget PRIVATE Qt6::Core5Compat)
- QMakeを使用する場合
QT += core5compat
ソースコードファイルにおいて、QTextCodec
クラスをインクルードする。
#include <QTextCodec>
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QString str = codec->toUnicode(byteArray);
UTF-8から他の文字コードへの変換
QString::fromLocal8Bit()
Visual StudioとQtを連携する場合、文字列リテラルはソースコードのファイルの文字コードに関わらず、
ロケールの文字コード(WindowsならShift-JIS)に変換してコンパイルされるため、
現在のロケールに合わせた文字コードで変換するQString::fromLocal8Bit()を使用する。
QString strU8 = QString::fromLocal8Bit("テスト");
ui->label->setText(strU8);
QString::fromUtf8()
Visual Studio 2015以降とQtを連携する場合、Unicode文字列リテラルに対応しているため、
接頭辞u8を付加することで、UTF-8のまま(ロケールの文字コードに変換されることなく)コンパイルすることができる。
QString strU8 = QString::fromUtf8(u8"テスト");
ui->label->setText(strU8);
pragmaの指定
Visual Studio 2013以前とQtを連携する場合、pragmaを指定することで、文字列リテラルをUTF-8に変換することができる。
#pragma execution_character_set("utf-8")
その他の方法
以下のように、クラスに静的メソッドを定義して使用する方法でもよい。
std::string MainWindow::UTF16_to_UTF8(const QString &src)
{
return src.toUtf8().toStdString();
}
UTF-16から他の文字コードへの変換
現在のロケールへの変換
UTF-16から現在のロケール(Windowsの場合はShift-JIS)へ変換する。
std::string MainWindow::UTF16_to_Locale(const QString &src)
{
return src.toLocal8Bit().toStdString();
}
Shift-JISへの変換
UTF-16からShift-JISへ変換する。
std::string MainWindow::UTF16_to_SJIS(const QString &src)
{
QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
QByteArray encoded = codec->fromUnicode(src);
return encoded.toStdString();
}
EUC-JPへの変換
UTF-16からEUC-JPへ変換する。
std::string MainWindow::UTF16_to_EUC(const QString &src)
{
QTextCodec *codec = QTextCodec::codecForName("EUC-JP");
QByteArray encoded = codec->fromUnicode(src);
return encoded.toStdString();
}
Shift-JISからUTF-16への変換
Shift-JISからUTF-16へ変換する。
QString MainWindow::SJIS_to_UTF16(const std::string &src)
{
QTextCodec *codec = QTextCodec::codecForName("Shift-JIS");
return codec->toUnicode(src.c_str());
}
EUC-JPからUTF-16への変換
EUC-JPからUTF-16へ変換する。
QString MainWindow::EUC_to_UTF16(const std::string &src)
{
QTextCodec *codec = QTextCodec::codecForName("EUC-JP");
return codec->toUnicode(src.c_str());
}