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

Published Thursday June 30th, 2011
Leave a comment
Posted in リサーチプロジェクト | Tags:

この記事は 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

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in リサーチプロジェクト | Tags:

Leave a Reply

Your email address will not be published.

Get started today with Qt Download now