ロケールを用いた文字列のコレーション

この記事は Qt Blog の "String collation with locales" を翻訳したものです。
執筆: ddenis, 2011年6月14日

Carlos が 数ヶ月前に 書いたように Qt Earth Team では Qt の国際化、ローカライズのサポートを進めてきました。既に以下のいくつかの機能を実装しています。

  • Linux/Unix で LC_MESSAGES や LC_TIME 等の環境変数を考慮するように変更
  • QLocale に文字種別のサポートを追加
  • 通貨のサポートを追加(不十分だというフィードバックがあったため、リリース前にさらに機能を追加しようと思っています)
  • アプリケーションの翻訳のために OS から対応言語を取得、週の最初の曜日、ウィークデー、文字列のクォート、複数の文字列の結合、等々

我々の TODO リストにあるもう1つは、コレーション(collation)のサポート(QTBUG-17104)です。(これはとても複雑な話なので)馴染みが無い方のために説明すると、コレーションとは文字列を並べる順番のことです。例えば “coté” と “côte” という2つの文字列があった場合に、フランスのフランス語のロケール(fr-FR)では前者が前になるのに対して、カナダのフランス語のロケール(fr-CA)では、後者が前になります。現在の Qt でもローカライズに対応した文字列比較([qt "QString::localeAwareCompare" l=qstring m=#localeAwareCompare])ができますが、これには2つの問題があります。1つはシステムロケールしか使えないこと(どのロケールのルールかを指定できない)、もう1つは「デフォルト」の比較ルールを使用することで、これは(例えば "file10" と "file2" のような)数字の比較などを設定する方法が無いことを意味します。というわけで、私は QtCollator クラスのドラフトを実装をしてみました。このクラスは ICU ライブラリのラッパで、コレーションの機能を Qt のスタイルの API で提供します。

class QtCollator
{
public:
enum Strength {
PrimaryStrength = 1,
BaseLetterStrength = PrimaryStrength,

SecondaryStrength = 2,
AccentsStrength = SecondaryStrength,

TertiaryStrength = 3,
CaseStrength = TertiaryStrength,

QuaternaryStrength = 4,
PunctuationStrength = QuaternaryStrength,

IdenticalStrength = 5,
CodepointStrength = IdenticalStrength
};

enum Option {
PreferUpperCase = 0x01,
PreferLowerCase = 0x02,
FrenchCollation = 0x04,
DisableNormalization = 0x08,
IgnorePunctuation = 0x10,
ExtraCaseLevel = 0x20,
HiraganaQuaternaryMode = 0x40,
NumericMode = 0x80
};
Q_DECLARE_FLAGS(Options, Option)

QtCollator(const QLocale &locale = QLocale());
QtCollator(const QtCollator &);
~QtCollator();
QtCollator &operator=(const QtCollator &);

void setLocale(const QLocale &locale);
QLocale locale() const;

void setStrength(Strength);
Strength strength() const;

void setOptions(Options);
Options options() const;

enum CasePreference {
IgnoreCase = 0x0,
UpperCase = 0x1,
LowerCase = 0x2
};

bool isCaseSensitive() const;
CasePreference casePreference() const;
void setCasePreference(CasePreference c);

void setNumericMode(bool on);
bool numericMode() const;

int compare(const QString &s1, const QString &s2) const;
int compare(const QStringRef &s1, const QStringRef &s2) const;
bool operator()(const QString &s1, const QString &s2) const
{ return compare(s1, s2) < 0; }

QByteArray sortKey(const QString &string) const;
};

簡単なベンチマークでは(ICU の実装を使用した) QtCollator では QString::localeAwareCompare (つまり strcoll())に比べて Linux では 30 倍速く、Windows では(CompareString を使用する) localeAwareCompare よりも 5 倍速いという結果でした。

現在のコードはリサーチ用のリポジトリにあり、Qt 内部のものには一切依存していません。単に libICU ライブラリをラッピングしたもので、アドオンとしてアプリケーションから使用可能です。プラットフォームにあるかどうか分からないサードーパーティーのライブラリに依存しているものを Qt に含めるのは難しいのが現実で、さらに ICU が提供する機能のいくつかが Qt が既に持っているものと重複しているという問題もあります。1つの代替案は Unicode Collation Algorithm を実装し、CLDR のデータを直接使用する(これは既に QLocale のデータで行っています)ことです。

今のところ Qt のコレーションがどうなるかについての明確な答えはありませんが、Qt Contributors' Summit でこれが議題にあがり、今後の方向性が決まることを期待しています。

ソースコード: https://qt.gitorious.org/qt-labs/qtcollator

サンプルアプリケーション: https://qt.gitorious.org/qt-labs/qtcollator/blobs/master/qsort/main.cpp#line86


Blog Topics:

Comments