WonderflMigemo

by uwi
♥0 | Line 542 | Modified 2010-12-04 01:43:18 | MIT License
play

ActionScript3 source code

/**
 * Copyright uwi ( http://wonderfl.net/user/uwi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/otR3
 */

// Google IME APIをつかったmigemoっぽいの
// 通信が間に合わないときは"><"がかえる

// あんまりGPLにしたくないです
package {
    import flash.display.Sprite;
    import flash.text.TextField;
    import jp.progression.commands.net.*;
    import flash.net.*;
    import flash.display.Bitmap;
    import flash.utils.*;
    
    import flash.events.*;
    import com.bit101.components.*;
    
import com.adobe.serialization.json.JSON;

    public class Test extends Sprite {
        private var _tf : TextField;
        private var _it : InputText;
        
        public function Test() {
            _tf = new TextField();
            _tf.width = 465;
            _tf.height = 465;
            _tf.y = 40;
            addChild(_tf);
            
            WonderflMigemo._tf = _tf;
            _it = new InputText(this, 100, 20, "", function(e:Event) : void{
                WonderflMigemo.complement(_it.text, function(reg : String) : void{
                    tr(_it.text + "\t" + reg);
                });
            });
        }

        private function tr(...o : Array) : void
        {
            _tf.appendText(o + "\n");
        }
    }
}

import com.adobe.serialization.json.JSON;
import flash.events.Event;
import flash.net.*;
import flash.utils.*;
import flash.text.*;

class WonderflMigemo {
    public static var _tf : TextField;
    public static var _blocking : Boolean = false;
    
    /**
     * 正規表現を作成
     */
    public static function complement(query : String, callback : Function) : void
    {
        if(_blocking){
            callback("><");
            return;
        }
        
        var ret : Vector.<String> = new Vector.<String>();
        ret.push(query);
        if (query.length == 0){
            callback(concatVec(ret));
            return;
        }
        
        // 英字の半角をexpand
        ret.push(expandAlphabet(query));
        
        query = convertHiraganaToKatakana(query);
        var expandedRomans : Vector.<String> = expandConsonant(query.replace(/([sktpgdzc]){2,}/g, "xtu$1"));
        var reqmap : Object = {};
        for each(var eroman : String in expandedRomans) {
            var kata : String = convertRomanToKatakana(eroman);
            ret.push(kata);
            var hira : String = convertKatakanaToHiragana(kata);
            ret.push(hira);
            reqmap[hira] = hira;
        }
        var reqs : Array = [];
        for(var key : String in reqmap){
            reqs.push(key);
        }
        
        if(reqs.length != 1){
            ret.sort(compstr); // ソート
            ret = uniq(ret); // 同一表現を除去
            callback(concatVec(ret));
        }else{
            _blocking = true;
            var proxyUrl : String = "http://uwiproxy.appspot.com/simpleproxy?url=";
            var url : String = "http://www.google.com/transliterate?langpair=ja-Hira|ja%26text=";

            var x : String = reqs[0];
            var nurl : String = proxyUrl + url + escapeMultiByte(x); 
            var ul : URLLoader = new URLLoader();
            ul.dataFormat = URLLoaderDataFormat.BINARY;
            ul.load(new URLRequest(nurl));
            ul.addEventListener(Event.COMPLETE, function(e : Event) : void
            {
                ul.removeEventListener(Event.COMPLETE, arguments.callee);
                var ba : ByteArray = ul.data as ByteArray;
                var str : String = ba.readMultiByte(ba.length, "MS932");
                str = str.replace(/,\s*\]/gs, "]"); // JSON規約違反を直す
                var json : Object = JSON.decode(str);
                
                if(json.length == 1){
                    for each(var ss : String in json[0][1]){
                        ret.push(ss);
                    }
                    ret.sort(compstr); // ソート
                    ret = uniq(ret); // 同一表現を除去
                    
                    _blocking = false;
                    callback(concatVec(ret));
                }else{
                    var reg : String = "";
                    for each(var seg : Object in json){
                        if(seg[1].length > 0){
                            var vec : Vector.<String> = new Vector.<String>();
                            for each(var st : String in seg[1]){
                                vec.push(st);
                            }
                            reg += "(" + concatVec(vec) + ")";
                        }
                    }
                    _blocking = false;
                    callback(concatVec(ret) + "|(" + reg + ")");
                }
            });
        }
    } 
    
    
    /**
     * 正規表現のメタ文字をエスケープして|でつなぐ
     * @param    vec
     * @return
     */
    public static function concatVec(vec : Vector.<String>) : String
    {
        var s2 : String = "";
        var s1 : String = "";
        for each(var str : String in vec) {
            var s : String = escapeRegex(str);
            if(s.length == 1){
                s1 += s;
            }else{
                s2 += s + "|";
            }
        }
        if(s1.length == 0 && s2.length == 0)return "";
        if(s1.length == 0)return s2.substring(0, s2.length - 1);
        if(s1.length == 1)return s2 + s1;
        return s2 + "[" + s1 + "]";
    }
    
    public static function escapeRegex(str : String) : String
    {
        return str.replace(/([\*\+\.\?\{\}\(\)\[\]\^\$\-\|\/\\])/g, "\\$1");
    }

    
    /**
     * 隣接する共通文字列を除去
     * @param    vec
     * @return
     */
    private static function uniq(vec : Vector.<String>) : Vector.<String>
    {
        var ret : Vector.<String> = new Vector.<String>();
        
        var prev : String = null;
        for each(var str : String in vec) {
            if (str.length == 0 || prev == str) continue;
            ret.push(str);
            prev = str;
        }
        
        return ret;
    }
    
    /**
     * 簡単な文字列比較関数
     * @param    a
     * @param    b
     * @return
     */
    private static function compstr(a : String, b : String) : int
    {
        return a < b ? -1 : 1;
    }
    
    /**
     * 半角英数を全角英数に変換
     * @param    src
     * @return
     */
    private static function expandAlphabet(src : String) : String
    {
        var vec : Array = new Array();
        for (var i : int = 0; i < src.length; i++) {
            var c : int = src.charCodeAt(i);
            if (c >= 0x0021 && c <= 0x007e) {
                c += (0xff01 - 0x0021);
            }
            vec.push(c);
        }
        return String.fromCharCode.apply(String, vec);
    }
    
    /**
     * 全角ひらがなを全角カタカナに変換
     * @param    kana
     * @return
     */
    private static function convertHiraganaToKatakana(kana : String) : String
    {
        kana = kana.replace(/う゛/g, "ヴ");
        var vec : Array = [];
        for (var i : int = 0; i < kana.length; i++) {
            var c : int = kana.charCodeAt(i);
            if (c >= 0x3041 && c <= 0x3093) {
                c += (0x30a1 - 0x3041);
            }
            vec.push(c);
        }
        return String.fromCharCode.apply(String, vec);
    }
    
    /**
     * 全角カタカナを全角ひらがなに変換
     * @param    kana
     * @return
     */
    private static function convertKatakanaToHiragana(kana : String) : String
    {
        kana = kana.replace(/ヴ/g, "う゛");
        var vec : Array = [];
        for (var i : int = 0; i < kana.length; i++) {
            var c : int = kana.charCodeAt(i);
            if (c >= 0x30a1 && c <= 0x30f3) {
                c += (0x3041 - 0x30a1);
            }
            vec.push(c);
        }
        return String.fromCharCode.apply(String, vec);
    }
    
    /**
     * ローマ字を全角カタカナに変換
     * @param    roman
     * @return
     */
    private static function convertRomanToKatakana(roman : String) : String
    {
        var ret : String = "";
        var p : int = 0;
        while(true) {
            for (var q : int = p + 1; q <= roman.length; q++) {
                var str : String = roman.substring(p, q);
                var kata : String = ROMA2KATA[str];
                if (kata != null) {
                    ret += kata;
                    p = q;
                    break;
                }else if(str.charAt(0) == "n" && str.length == 2){
                    ret += "ン";
                    q--;
                    p = q;
                    break;
                }
            }
            if (q > roman.length)break;
        }
        return ret;
    }
    
    /**
     * ローマ字を補完
     * @param    roman
     * @return
     */
    private static function expandConsonant(roman : String) : Vector.<String>
    {
        var ret : Vector.<String> = new Vector.<String>();
        if (roman.length == 0) return ret;
        var lastc : int = roman.charCodeAt(roman.length - 1);
        switch(lastc){
        case 0x63: // 'c'
            ret.push(roman + "hi");
            break;
        case 0x78: // 'x'
            ret.push(roman + "tu");
            ret.push(roman + "ya");
            ret.push(roman + "yu");
            ret.push(roman + "yo");
            break;
        case 0x79: // 'y'
            ret.push(roman + "a");
            ret.push(roman + "u");
            ret.push(roman + "o");
            break;
        case 0x6e: // 'n'
            ret.push(roman + "n");
        case 0x62: // 'b'
        case 0x64: // 'd'
        case 0x66: // 'f'
        case 0x67: // 'g'
        case 0x68: // 'h'
        case 0x6a: // 'j'
        case 0x6b: // 'k'
        case 0x6d: // 'm'
        case 0x70: // 'p'
        case 0x72: // 'r'
        case 0x73: // 's'
        case 0x74: // 't'
        case 0x77: // 'w'
        case 0x7a: // 'z'
            ret.push(roman + "a");
            ret.push(roman + "i");
            ret.push(roman + "u");
            ret.push(roman + "e");
            ret.push(roman + "o");
            if (roman.slice(-2) != "sh" && lastc != 0x6e) {
                var c : String = String.fromCharCode(lastc);
                var base : String = roman.slice(0, -1) + "xtu" + c;
                ret.push(base + "a");
                ret.push(base + "i");
                ret.push(base + "u");
                ret.push(base + "e");
                ret.push(base + "o");
            }
            break;
        default:
            ret.push(roman);
            break;
        }
        return ret;
    }
    
    // ローマ字→全角カタカナ変換テーブル
    private static const ROMA2KATA : Object = {
        "a" : "ア",
        "i" : "イ",
        "u" : "ウ",
        "e" : "エ",
        "o" : "オ",
        "ka" : "カ",
        "ki" : "キ",
        "ku" : "ク",
        "ke" : "ケ",
        "ko" : "コ",
        "sa" : "サ",
        "si" : "シ",
        "su" : "ス",
        "se" : "セ",
        "so" : "ソ",
        "ta" : "タ",
        "ti" : "チ",
        "tu" : "ツ",
        "te" : "テ",
        "to" : "ト",
        "na" : "ナ",
        "ni" : "ニ",
        "nu" : "ヌ",
        "ne" : "ネ",
        "no" : "ノ",
        "ha" : "ハ",
        "hi" : "ヒ",
        "hu" : "フ",
        "he" : "ヘ",
        "ho" : "ホ",
        "ma" : "マ",
        "mi" : "ミ",
        "mu" : "ム",
        "me" : "メ",
        "mo" : "モ",
        "ya" : "ヤ",
        "yi" : "イ",
        "yu" : "ユ",
        "ye" : "イェ",
        "yo" : "ヨ",
        "ra" : "ラ",
        "ri" : "リ",
        "ru" : "ル",
        "re" : "レ",
        "ro" : "ロ",
        "wa" : "ワ",
        "wi" : "ヰ",
        "wu" : "ウ",
        "we" : "ヱ",
        "wo" : "ヲ",
        "ga" : "ガ",
        "gi" : "ギ",
        "gu" : "グ",
        "ge" : "ゲ",
        "go" : "ゴ",
        "za" : "ザ",
        "zi" : "ジ",
        "zu" : "ズ",
        "ze" : "ゼ",
        "zo" : "ゾ",
        "da" : "ダ",
        "di" : "ヂ",
        "du" : "ヅ",
        "de" : "デ",
        "do" : "ド",
        "ba" : "バ",
        "bi" : "ビ",
        "bu" : "ブ",
        "be" : "ベ",
        "bo" : "ボ",
        "pa" : "パ",
        "pi" : "ピ",
        "pu" : "プ",
        "pe" : "ペ",
        "po" : "ポ",
        "la" : "ァ",
        "li" : "ィ",
        "lu" : "ゥ",
        "le" : "ェ",
        "lo" : "ォ",
        "lya" : "ャ",
        "lyi" : "ィ",
        "lyu" : "ュ",
        "lye" : "ェ",
        "lyo" : "ョ",
        "xa" : "ァ",
        "xi" : "ィ",
        "xu" : "ゥ",
        "xe" : "ェ",
        "xo" : "ォ",
        "xya" : "ャ",
        "xyi" : "ィ",
        "xyu" : "ュ",
        "xye" : "ェ",
        "xyo" : "ョ",
        "kya" : "キャ",
        "kyi" : "キィ",
        "kyu" : "キュ",
        "kye" : "キェ",
        "kyo" : "キョ",
        "gwa" : "グァ",
        "gwi" : "グィ",
        "gwu" : "グゥ",
        "gwe" : "グェ",
        "gwo" : "グォ",
        "gya" : "ギャ",
        "gyi" : "ギィ",
        "gyu" : "ギュ",
        "gye" : "ギェ",
        "gyo" : "ギョ",
        "sha" : "シャ",
        "shi" : "シ",
        "shu" : "シュ",
        "she" : "シェ",
        "sho" : "ショ",
        "swa" : "スァ",
        "swi" : "スィ",
        "swu" : "スゥ",
        "swe" : "スェ",
        "swo" : "スォ",
        "sya" : "シャ",
        "syi" : "シィ",
        "syu" : "シュ",
        "sye" : "シェ",
        "syo" : "ショ",
        "tha" : "テャ",
        "thi" : "ティ",
        "thu" : "テュ",
        "the" : "テェ",
        "tho" : "テョ",
        "tsa" : "ツァ",
        "tsi" : "ツィ",
        "tsu" : "ツ",
        "tse" : "ツェ",
        "tso" : "ツォ",
        "twa" : "トァ",
        "twi" : "トィ",
        "twu" : "トゥ",
        "twe" : "トェ",
        "two" : "トォ",
        "tya" : "チャ",
        "tyi" : "チィ",
        "tyu" : "チュ",
        "tye" : "チェ",
        "tyo" : "チョ",
        "nya" : "ニャ",
        "nyi" : "ニィ",
        "nyu" : "ニュ",
        "nye" : "ニェ",
        "nyo" : "ニョ",
        "hya" : "ヒャ",
        "hyi" : "ヒィ",
        "hyu" : "ヒュ",
        "hye" : "ヒェ",
        "hyo" : "ヒョ",
        "bya" : "ビャ",
        "byi" : "ビィ",
        "byu" : "ビュ",
        "bye" : "ビェ",
        "byo" : "ビョ",
        "pya" : "ピャ",
        "pyi" : "ピィ",
        "pyu" : "ピュ",
        "pye" : "ピェ",
        "pyo" : "ピョ",
        "mya" : "ミャ",
        "myi" : "ミィ",
        "myu" : "ミュ",
        "mye" : "ミェ",
        "myo" : "ミョ",
        "rya" : "リャ",
        "ryi" : "リィ",
        "ryu" : "リュ",
        "rye" : "リェ",
        "ryo" : "リョ",
        "ca" : "カ",
        "ci" : "シ",
        "cu" : "ク",
        "ce" : "セ",
        "co" : "コ",
        "cha" : "チャ",
        "chi" : "チ",
        "chu" : "チュ",
        "che" : "チェ",
        "cho" : "チョ",
        "fa" : "ファ",
        "fi" : "フィ",
        "fu" : "フ",
        "fe" : "フェ",
        "fo" : "フォ",
        "fwa" : "ファ",
        "fwi" : "フィ",
        "fwu" : "フゥ",
        "fwe" : "フェ",
        "fwo" : "フォ",
        "fya" : "フャ",
        "fyi" : "フィ",
        "fyu" : "フュ",
        "fye" : "フェ",
        "fyo" : "フョ",
        "ja" : "ジャ",
        "ji" : "ジ",
        "ju" : "ジュ",
        "je" : "ジェ",
        "jo" : "ジョ",
        "jya" : "ジャ",
        "jyi" : "ジィ",
        "jyu" : "ジュ",
        "jye" : "ジェ",
        "jyo" : "ジョ",
        "qa" : "クァ",
        "qi" : "クィ",
        "qu" : "ク",
        "qe" : "クェ",
        "qo" : "クォ",
        "qwa" : "クァ",
        "qwi" : "クィ",
        "qwu" : "クゥ",
        "qwe" : "クェ",
        "qwo" : "クォ",
        "qya" : "クャ",
        "qyi" : "クィ",
        "qyu" : "クュ",
        "qye" : "クェ",
        "qyo" : "クョ",
        "va" : "ヴァ",
        "vi" : "ヴィ",
        "vu" : "ヴ",
        "ve" : "ヴェ",
        "vo" : "ヴォ",
        "vya" : "ヴャ",
        "vyi" : "ヴィ",
        "vyu" : "ヴュ",
        "vye" : "ヴェ",
        "vyo" : "ヴョ",
        "nn" : "ン",
        "n'" : "ン",
        "xn" : "ン",
        "ltu" : "ッ",
        "xtu" : "ッ",
        "lwa" : "ヮ",
        "xwa" : "ヮ",
        "lka" : "ヵ",
        "xka" : "ヵ",
        "lke" : "ヶ",
        "xke" : "ヶ",
        "kwa" : "クァ",
        "-" : "ー",
        "~" : "~",
        "," : "、",
        "." : "。",
        "[" : "「",
        "]" : "」",
        "mba" : "ンバ",
        "mbi" : "ンビ",
        "mbu" : "ンブ",
        "mbe" : "ンベ",
        "mbo" : "ンボ",
        "mpa" : "ンパ",
        "mpi" : "ンピ",
        "mpu" : "ンプ",
        "mpe" : "ンペ",
        "mpo" : "ンポ",
        "mma" : "ンマ",
        "mmi" : "ンミ",
        "mmu" : "ンム",
        "mme" : "ンメ",
        "mmo" : "ンモ",
        "tcha" : "ッチャ",
        "tchi" : "ッチ",
        "tchu" : "ッチュ",
        "tche" : "ッチェ",
        "tcho" : "ッチョ"
    };
}