カテゴリー
Technologies

MeCab+python+JavaScriptでサイトにルビを振る

標題の通り。意外と簡単にできたので共有します。

※正規表現で先読みと後読みのアサーションを使っているため、最新のEcmaScriptでないと動作しません…PC版Chromeでしか動作しません…なんとかしたい…。

python:

#coding: utf-8

from mod_python import apache, util
import re
import json
import MeCab

def handler(req):
    # テキスト取得
    fs  = util.FieldStorage(req, True)
    q   = fs.getfirst("q", "")

    if q:
        tagger  = MeCab.Tagger("-Oyomi")
        node    = tagger.parseToNode(q)

        wordTable   = []
        a2n_regexp  = re.compile("^[あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわゐゑをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽぁぃぅぇぉっゃゅょアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヰヱヲンガギグゲゴザジズゼゾダヂズデドバビブベボパピプペポァィゥェォッャュョヴ]+$")
        while node:
            wordTypes   = node.feature.split(',')
            if node.surface != "" and \
                len(wordTypes) >= 8 and \
                not a2n_regexp.match(node.surface) and \
                wordTypes[7] != node.surface:
                wordTable.append({
                    "y": wordTypes[7] or "*",
                    "k": node.surface or ""
                })
            node    = node.next
        sendJson(req, True, wordTable)

    else:
        sendJson(req, False)
    
    return apache.OK

# JSON形式で返答を返す。
def sendJson(req, result = False, returnValue = []):
    req.content_type    = "application/json; charset=utf-8"
    req.write(json.dumps({"result": result, "words": returnValue}, False, False))


JavaScript:

"use esversion:6";

(function($, d, w, undef) {
    "use strict";

    $(d).on("click", ".furigana-toggler", function(e) {
        if (!$(this).hasClass("on")) {
            $(this).remove();
            furiganaOn();
        }
        e.preventDefault()
    })

    function furiganaOn() {
        $("body").find("*:not([nodeType=1])").each(function() {
            let node = $(this);
            if (node.text() !== "") {
                $.post(
                    "/py/mecab.py/getFurigana",
                    {
                        q : node.text()
                    },
                    function(json) {
                        if (json.result === true && json.words !== undef) {
                            let text  = node.html();
                            let max   = json.words.length;
                            for (let i = 0; i < max; i++) {
                                let regex = new RegExp("(?<!<ruby>[^<>]*)" + json.words[i].k + "(?![^<]*<rt>" + json.words[i].y + "</rt></ruby>)");
                                text = text.replace(
                                    regex,
                                    "<ruby>" + json.words[i].k + "<rp>[</rp><rt>" + json.words[i].y + "</rt><rp>]</rp></ruby>"
                                );
                            }
                            node.html(text);
                        }
                    },
                    "json"
                );
            }
        });
    }
    
    function furiganaOff() {
        $("ruby.furigana, rp.furigana, rt.furigana").unwrap();
    }
})(jQuery, document, window);

pythonの方には何らかの認証機構をつけなければいけませんが、ひとまずこんな感じです。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください