ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Qt(B5) Qt のQStringとUTF16について

公開日| 2009年09月12日 | コメントはまだありません。
概要 :
 今回は、QtのQStringについての話です。
QStringは、非常に便利な文字列操作を行えるクラスで、QWidget継承クラスでの文字列の取り扱いは、このQStringもしくはQStringの元QCharで行うのが普通です。

では、QStringの実体は、どのようになっているでしょうか?

Qtの世界で閉じたアプリケーションを作成している場合は、文字列は、すべてQStringで行っておけば、何も問題になりません。
また、クロスプラットフォームでのアプリケーション作成を行う予定がない方にとっても、それほど問題にならないかもしれません。

しかし、そうでない方にとっては、非常に大事な問題になることがあります。 例えば、別のライブラリとQtライブラリを混合させる場合などです。
そのような時、その別のライブラリでは、文字列を何で扱っているでしょう。
C/C++で用いる一般的な型、char,wchar_tかもしれません。STLのstring,wstringかもしれません。Windowsであれば、MFCのCStringかもしれません。
QStringで扱っていれば、ほとんど問題にならないでしょう。
しかし、上記のように異なる型、クラスを使っている場合、Qtアプリケーションで取り扱えるようにQStringへの変換が、常に、つきまといます。

このようなとき、QStringの性格を少し理解していると、プログラミングの仕方の手助けになると思います。
では、早速、簡単に解説してみたいと思います。



少し、文字列と文字コード、C/C++での型の関係を整理しておきましょう。

C/C++で文字列は、char型で扱います。この型に情報として設定される文字コードは、ASCIIコードが用いられるのが一般的です。 これは、一般的と記述したように、あくまで、多くのコンパイラが、ASCIIコードを扱うということに過ぎません。 例えば、日本語の場合では、Windowsでは、(少し御幣がありますが)ASCIIコードの拡張版としてShiftJisコードを用いたりします。 UNIX系の場合では、(少し御幣がありますが)ASCIIコードの拡張版としてEUCコードを用いたりします。
このように、char型に収まる文字コード情報は、必ずしも決まっているわけではありません。 日本語に限らす、英数字でも、その昔は、色々なOSが存在していましたので、ASCIIコード以外の文字列を設定するコンパイラなどもありました。
ここで、注意すべきは、文字コードは、コンパイラの仕様であり、C/C++の言語仕様でないことに注意しなければなりません。

続けて、ワイド文字の定義です。ワイド文字は、言葉のとおり、1バイトより多くの情報で表現する文字を言います。 これも誤解されがちですが、ワイド文字が、UNICODEと限らないことに注意しなければなりません。
確かに、UTF-16,UTF-32の仕様は、ワイド文字といえます。しかし、逆は、必ずしも言えないことに注意する必要があります。

更に、C/C++でワイド文字の型は、wchar_tで表現します。Cの世界では、通常、shortを割り当てられますが、wchar_tは、予約語ですから、コンパイラに依存します。
Windowsの世界では、wchar_tはshortと同じ2バイトデータとして扱われます。
また、Windowsの世界だけを考えれば、ワイド文字は、UNICODE(UTF-16)と同じと考えても、ほとんどの場合で、問題にならないかもしれません。(これが混乱の元です。)
しかし、他のOSでは、そうとは限らないことを、先の文字列(char)の話でも理解いただけると思います。また、wchar_tが、他のOSでも2バイトかどうかもわかりません。

このことを踏まえると、以下のようなリテラルの記述例が、非常に問題であることが理解できると思います。
1
2
char     c1 = "abcde";
wchar_t  c2 = L"abcde";
この記述では、c2には、UNICODE(UTF-16)が入ると思うかもしれません。しかし、Windows以外で、それが保障されるとは限りません。
(L"xxxx"の記述は、ワイド文字列を意味します。先にも記述したように、ワイド文字列が必ずしもUTF-16ではないことに注意する必要があります。)

実際に、C++0x(将来のC++の標準仕様)では、 char16_t(2バイト文字列), char32_t(4バイト文字列) という予約語が新たに追加されています。 また、リテラルについても、UNICODEを設定する場合、以下のような記述を行うように仕様が追加されています。

1
2
3
4
char     c1 = 'a';
wchar_t  c2 = L'a';
char16_t c3 = u'a';
char32_t c4 = U'a';

この仕様は、Visual Studio 2010で組み込まれる予定だそうです。
QStringの内部で扱っている文字コードは何でしょうか?
答え
UNICODE(UTF-16) です。

このことは、Qtのクラスリファレンスにも記載があります。
しかし、エンディアンについては、QStringでは、触れていません。

UTF-16のエンディアンは、どちらを採用しているでしょうか?
答え
(通常のエンディアンと同じように)システム(OS)に依存します。

明確に確認したい場合は、以下のヘッダを確認すると良いでしょう。

%Qtインストール先ディレクトリ%\qt\src\corelib\global\qconfig.h

1
2
3
4
5
/* Machine byte-order */
#define Q_BIG_ENDIAN 4321
#define Q_LITTLE_ENDIAN 1234
#define Q_BYTE_ORDER Q_LITTLE_ENDIAN
        ^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^
Q_BYTE_ORDER という名前の定義に、Q_BIG_ENDIAN / Q_LITTLE_ENDIAN のいずれかが定義されています。
(ここでは、Q_LITTLE_ENDIANを定義していますから、当然、UTF-16LE(リトルエンディアン)となります。)

※内部で扱っている場合は、BOMはつきません。

他の型、クラスからQStringへ変換する場合、最も効率の良いやり方は、どのようなやり方でしょうか?
ここでは、Windowsでの実績をもとに話をします。そのため、少し、他のOSで実証した場合、異なるかもしれません。

答え
QStringでは、staticなメソッドで、色々な変換パターンを用意しています。
別の文字コードから変換が必要な場合は、QStringのstaticなメソッドを使った方が早いでしょう。
参考:ICUライブラリを用いて変換するより、QStringのstaticなメソッド(fromLocal8Bit)を使った方が倍くらい早かったです。(ShiftJisからUTF-16への変換の場合)

同じUTF-16の場合、そのアドレス(short *)と文字数を、QStringのsetUtf16(const ushort *,int)で設定する方が早いでしょう。
(同じコードの場合は、staticなメソッド(fromUtf16)で設定するより、setUtf16で設定する方が早いことに気をつけておいた方が良いでしょう。)


日本語20文字(ShiftJis)をUTF-16へ、1000000回、変換した時の処理速度計測結果
利用したライブラリ 利用した関数(メソッド) 実測データ(秒)
Windows Api MultiByteToWideChar 1.7
Qtライブラリ QString::fromLocal8Bit 2.0
icuライブラリ ucnv_toUnicode
※単純なサブルーチン処理なので、毎回、ucnv_open/ucnv_closeを実施しています。
7.2
icuライブラリ ucnv_convert 7.4


やっぱり、Windowsの中では、WindowsのAPIを使うのが、より良い選択だといえますね。
ただ、意外に、ICUの変換処理は、遅いんですね。(プログラミングを間違ったのかなと確認してみましたが、ucnv_open --> ucnv_toUnicode --> ucnv_closeの流れなので、間違いはないと思うんですけどね。)

それにしても、Qtライブラリは、より良い成績です。
と、感心していたら、内部的には、WIN32の場合、WindowsAPIをそのまま使っていました。ただのラッパーですから、そのラップしている分、遅いだけなんですね。

もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。


コメント

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ