Qt 5 の未来は明るいブログ

QtQuick で全角文字を半角に変換する

Published: 2013-03-28 / Last modified: 2013-03-28

はじめに

昨日書いた Qt 5 で全角文字を半角に変換する #01 に以下のようなフィードバックがありました。

ここでいう「プラグイン」というのは QNeptunea という Nokia N9 上で動く Twitter Client の機能を拡張するプラグインで、「苦労」とは これ とか これ の変更のことを指しています。

パッチ を見てもらえるわかるかと思いますが、実際にこの機能の実装は 20行程度 で、Qt のバージョンに依存するようなコードではないので、Qt 4 でも簡単に同じ事が実現できます。

作ったもの

ということで、QtQuick 1.x から Transliterate するような 簡単なサンプルを作ってみました 。取得の仕方などは http://qtquick.me/ の「Readonly access」を参照してください。

import QtQuick 1.1
import me.qtquick.transliterator 0.1

Text {
id: halfwidth
Transliterator {
id: transliterator
type: 'Fullwidth-Halfwidth'
}
Component.onCompleted: halfwidth.text = transliterator.transliterate('123ABC')
}

のように使うことができます。便利ですね。

C++ 側

こんな感じに実装されています。

#include <QtDeclarative>

#include <unicode/utypes.h>
#include <unicode/unistr.h>
#include <unicode/translit.h>

class QTransliterator : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
    Q_PROPERTY(QStringList availableTypes READ availableTypes NOTIFY availableTypesChanged)
public:
    QTransliterator(QObject *parent = 0);

    const QString &type() const;
    const QStringList &availableTypes() const;

    Q_INVOKABLE QString transliterate(const QString &text);

public slots:
    void setType(const QString &type);

signals:
    void typeChanged(const QString &type);
    void availableTypesChanged(const QStringList &availableTypes);

private slots:
    void createTransliterator(const QString &type);

private:
    QString icu2qt(const icu::UnicodeString &string);
    icu::UnicodeString qt2icu(const QString &string);

private:
    QString m_type;
    QStringList m_availableTypes;
    icu::Transliterator *m_transliterator;
};

QTransliterator::QTransliterator(QObject *parent)
    : QObject(parent)
    , m_transliterator(0)
{
    int count = icu::Transliterator::countAvailableIDs();
    for (int i = 0; i < count; i++) {
        icu::UnicodeString id = icu::Transliterator::getAvailableID(i);
        m_availableTypes.append(icu2qt(id));
    }
    connect(this, SIGNAL(typeChanged(QString)), this, SLOT(createTransliterator(QString)));
}

const QString &QTransliterator::type() const
{
    return m_type;
}

void QTransliterator::setType(const QString &type)
{
    if (m_type == type) return;
    if (m_availableTypes.contains(type)) {
        m_type = type;
        emit typeChanged(type);
    } else {
        qWarning() << type << tr("is not supported");
        qWarning() << m_availableTypes;
    }
}

const QStringList &QTransliterator::availableTypes() const
{
    return m_availableTypes;
}

void QTransliterator::createTransliterator(const QString &type)
{
    if (m_transliterator) {
        delete m_transliterator;
        m_transliterator = 0;
    }

    UErrorCode status = U_ZERO_ERROR;
    m_transliterator = icu::Transliterator::createInstance(qt2icu(type), UTRANS_FORWARD, status);
}

QString QTransliterator::transliterate(const QString &text)
{
    QString ret;
    if (m_transliterator) {
        UnicodeString str = qt2icu(text);
        m_transliterator->transliterate(str);
        ret = icu2qt(str);
    }
    return ret;
}

QString QTransliterator::icu2qt(const icu::UnicodeString &string)
{
    int len = string.length();
    QString ret(len, Qt::Uninitialized);
    string.extract(0, len, reinterpret_cast<UChar *>(ret.data()));
    return ret;
}

icu::UnicodeString QTransliterator::qt2icu(const QString &string)
{
    return icu::UnicodeString::fromUTF8(string.toUtf8().constData());
}

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    qmlRegisterType<QTransliterator>("me.qtquick.transliterator", 0, 1, "Transliterator");
    QDeclarativeView view(QUrl("qrc:/transliterator.qml"));
    view.show();

    return app.exec();
}