본문 바로가기

Web/Javascript

자바스크립트로 변환한 나비 오토마타(Nabi)

/*
* Nabi on Javascript 0.1
* This program is based on Nabi 0.13
* nskystars at yahoo dot com
*/

/*
user defined functions:
    function user_commit(Array buf);
    function user_commit_keyval(char keyval);
    function user_preedit_insert(Array buf);
    function user_preedit_update(Array buf);

call nabi_automata_2(char keyval) to use hangul_automata

TODO:
    Support for Sebulsik(390, final...), Dvorak keyboards
*/

/* hangul.c */

function hangul_is_choseong(ch) { return (ch >= 0x1100 && ch <= 0x1159) ? 1 : 0; }
function hangul_is_jungseong(ch) { return (ch >= 0x1161 && ch <= 0x11a2) ? 1 : 0; }
function hangul_is_jongseong(ch) { return (ch >= 0x11a7 && ch <= 0x11f9) ? 1 : 0; }

function
hangul_choseong_to_cjamo(ch)
{
    var table = new Array(
        0x3131, /* 0x1100 */
        0x3132, /* 0x1101 */
        0x3134,
        0x3137,
        0x3138,
        0x3139,
        0x3141,
        0x3142,
        0x3143,
        0x3145,
        0x3146,
        0x3147,
        0x3148,
        0x3149,
        0x314a,
        0x314b,
        0x314c,
        0x314d, /* 0x1111 */
        0x314e /* 0x1112 */
    );

    if(ch < 0x1100 || ch > 0x1112)
        return ch;
    return table[ch - 0x1100];
}

function
hangul_jungseong_to_cjamo(ch)
{
    var table = new Array(
        0x314f, /* 0x1161 */
        0x3150, /* 0x1162 */
        0x3151,
        0x3152,
        0x3153,
        0x3154,
        0x3155,
        0x3156,
        0x3157,
        0x3158,
        0x3159,
        0x315a,
        0x315b,
        0x315c,
        0x315d,
        0x315e,
        0x315f,
        0x3160,
        0x3161,
        0x3162, /* 0x1174 */
        0x3163 /* 0x1175 */
    );
    if(ch < 0x1161 || ch > 0x1175)
        return 0;
    return table[ch - 0x1161];
}

function
hangul_jongseong_to_cjamo(ch)
{
    var table = new Array(
        0x3131, /* 0x11a8 */
        0x3132, /* 0x11a9 */
        0x3133,
        0x3134,
        0x3135,
        0x3136,
        0x3137,
        0x3139,
        0x313a,
        0x313b,
        0x313c,
        0x313d,
        0x313e,
        0x313f,
        0x3140,
        0x3141,
        0x3142,
        0x3144,
        0x3145,
        0x3146,
        0x3147,
        0x3148,
        0x314a,
        0x314b,
        0x314c,
        0x314d, /* 0x11c1 */
        0x314e /* 0x11c2 */
    );
    if(ch < 0x11a8 || ch > 0x11c2)
        return 0;
    return table[ch - 0x11a8];
}

function
hangul_choseong_to_jongseong(ch)
{
    var table = new Array(
        0x11a8, /* kiyeok */
        0x11a9,
        0x11ab,
        0x11ae,
        0x0,
        0x11af,
        0x11b7,
        0x11b8,
        0x0,
        0x11ba,
        0x11bb,
        0x11bc,
        0x11bd,
        0x0,
        0x11be,
        0x11bf,
        0x11c0,
        0x11c1,
        0x11c2
    );
    if(ch < 0x1100 || ch > 0x1112)
        return 0;
    return table[ch - 0x1100];
}

function
hangul_jongseong_to_choseong(ch)
{
    var table = new Array(
        0x1100, /* kiyeok */
        0x1101,
        0x1109,
        0x1102,
        0x110c,
        0x1112,
        0x1103,
        0x1105,
        0x1100,
        0x1106,
        0x1107,
        0x1109,
        0x1110,
        0x1111,
        0x1112,
        0x1106,
        0x1107,
        0x1109,
        0x1109,
        0x110a,
        0x110b,
        0x110c,
        0x110e,
        0x110f,
        0x1110,
        0x1111,
        0x1112
    );
    if(ch < 0x11a8 || ch > 0x11c2)
        return 0;
    return table[ch - 0x11a8];
}

function
hangul_jongseong_dicompose(ch)
{
    var table = new Array(
        0, 0x1100, /* jong kiyeok = cho kiyeok */
        0x11a8, 0x1100,
        0x11a8, 0x1109,
        0, 0x1102,
        0x11ab, 0x110c,
        0x11ab, 0x1112,
        0, 0x1103,
        0, 0x1105,
        0x11af, 0x1100,
        0x11af, 0x1106,
        0x11af, 0x1107,
        0x11af, 0x1109,
        0x11af, 0x1110,
        0x11af, 0x1111,
        0x11af, 0x1112,
        0, 0x1106,
        0, 0x1107,
        0x11b8, 0x1109,
        0, 0x1109,
        0x11ba, 0x1109,
        0, 0x110b,
        0, 0x110c,
        0, 0x110e,
        0, 0x110f,
        0, 0x1110,
        0, 0x1111,
        0, 0x1112
    );

    jong = table[(ch - 0x11a8) * 2];
    cho = table[(ch - 0x11a8) * 2 + 1];
    return new Array(jong, cho);
}

function
hangul_jamo_to_syllable(loc_choseong, loc_jungseong, loc_jongseong)
{
    var hangul_base = 0xac00;
    var choseong_base = 0x1100;
    var jungseong_base = 0x1161;
    var jongseong_base = 0x11a7;
    var njungseong = 21;
    var njongseong = 28;
    var ch;

    if(loc_jongseong == 0)
        loc_jongseong = 0x11a7;

    if(!(loc_choseong >= 0x1100 && loc_choseong <= 0x1112))
        return 0;
    if(!(loc_jungseong >= 0x1161 && loc_jungseong <= 0x1175))
        return 0;
    if(!(loc_jongseong >= 0x11a7 && loc_jongseong <= 0x11c2))
        return 0;

    loc_choseong -= choseong_base;
    loc_jungseong -= jungseong_base;
    loc_jongseong -= jongseong_base;

    ch = ((loc_choseong * njungseong) + loc_jungseong) * njongseong + loc_jongseong + hangul_base;
    return ch;
}


/* keyboard.h */

var keyboard_map_2 = new Array(
    0x0021, // exclam
    0x0022, // dbl quotes
    0x0023, // sharp
    0x0024, // dollar
    0x0025, // percent
    0x0026, // ampersand
    0x0027, // single quotes
    0x0028, // small bracket open
    0x0029, // small bracket close
    0x002A, // star
    0x002B, // plus
    0x002C, // comma
    0x002D, // minus
    0x002E, // period
    0x002F, // slash
    0x0030, // 0
    0x0031, // 1
    0x0032, // 2
    0x0033, // 3
    0x0034, // 4
    0x0035, // 5
    0x0036, // 6
    0x0037, // 7
    0x0038, // 8
    0x0039, // 9
    0x003A, // colon
    0x003B, // semicolon
    0x003C, // greater than
    0x003D, // eq
    0x003E, // less than
    0x003F, // question
    0x0040, // at
    0x1106, // mi-eum
    0x1172, // yu
    0x110E, // che-ot
    0x110B, // i-ung
    0x1104, // ssang di-gut
    0x1105, // ri-eul
    0x1112, // hi-eut
    0x1169, // oh
    0x1163, // ya
    0x1165, // euh
    0x1161, // a
    0x1175, // i
    0x1173, // eu
    0x116E, // u
    0x1164, // ssang a, i
    0x1168, // ssang euo, i
    0x1108, // ssang bi-eup
    0x1101, // ssang gi-eok
    0x1102, // ni-eun
    0x110A, // ssang si-eot
    0x1167, // yeo
    0x1111, // pi-eup
    0x110D, // ssang ji-eut
    0x1110, // ti-eut
    0x116D, // yo
    0x110F, // ki-euk
    0x005B, // large bracket open
    0x005C, // backslash
    0x005D, // large bracket close
    0x005E, // power
    0x005F, // underscore
    0x0060, // backquote
    0x1106, // mi-eum
    0x1172, // yu
    0x110E, // che-ot
    0x110B, // i-ung
    0x1103, // di-gut
    0x1105, // ri-eul
    0x1112, // hi-eut
    0x1169, // oh
    0x1163, // ya
    0x1165, // euh
    0x1161, // a
    0x1175, // i
    0x1173, // eu
    0x116E, // u
    0x1162, // a, i
    0x1166, // euo, i
    0x1107, // bi-eup
    0x1100, // gi-eok
    0x1102, // ni-eun
    0x1109, // si-eot
    0x1167, // yeo
    0x1111, // pi-eup
    0x110C, // ji-eut
    0x1110, // ti-eut
    0x116D, // yo
    0x110F, // ki-euk
    0x007B, // med bracket open
    0x007C, // strgt line vert
    0x007D, // med bracket close
    0x007E // tilde
);


/* ic.h */

// NabiIC
var index;
var stack = new Array();
var choseong = new Array();
var jungseong = new Array();
var jongseong = new Array();

function nabi_ic_is_empty() { return (choseong[0] == 0 && jungseong[0] == 0 && jongseong[0] == 0) ? 1 : 0; }


/* ic.c */

function
nabi_ic_push(ch)
{
    stack[++index] = ch;
}

function
nabi_ic_peek()
{
    if(index < 0)
        return 0;
    return stack[index];
}

function
nabi_ic_pop()
{
    if(index < 0)
        return 0;
    return stack[index--];
}

function
nabi_ic_buf_clear()
{
    index = -1;
    stack[0] = 0;
    stack[1] = 0;
    stack[2] = 0;
    stack[3] = 0;
    stack[4] = 0;
    stack[5] = 0;
    stack[6] = 0;
    stack[7] = 0;
    stack[8] = 0;
    stack[9] = 0;
    stack[10] = 0;
    stack[11] = 0;

    choseong[0] = 0;
    choseong[1] = 0;
    choseong[2] = 0;
    choseong[3] = 0;

    jungseong[0] = 0;
    jungseong[1] = 0;
    jungseong[2] = 0;
    jungseong[3] = 0;

    jongseong[0] = 0;
    jongseong[1] = 0;
    jongseong[2] = 0;
    jongseong[3] = 0;
}

function
nabi_ic_commit()
{
    var buf = new Array();
    if(nabi_ic_is_empty()) {
        return 0;
    }    
    var n = 0;

    var ch;
    ch = hangul_jamo_to_syllable(choseong[0], jungseong[0], jongseong[0]);
    if(ch)
        buf[n++] = ch;
    else {
        if(choseong[0]) {
            ch = hangul_choseong_to_cjamo(choseong[0]);
            buf[n++] = ch;
        }
        if(jungseong[0]) {
            ch = hangul_jungseong_to_cjamo(jungseong[0]);
            buf[n++] = ch;
        }
        if(jongseong[0]) {
            ch = hangul_jongseong_to_cjamo(jongseong[0]);
            buf[n++] = ch;
        }
    }
    user_commit(buf);
    nabi_ic_buf_clear();
}

function
nabi_ic_commit_keyval(keyval)
{
    user_commit_keyval(keyval);
}

function
nabi_ic_get_preedit_string()
{
    var ch;
    var buf = new Array();
    var n = 0;
    if(choseong[0]) {
        if(jungseong[0]) {
            ch = hangul_jamo_to_syllable(choseong[0], jungseong[0], jongseong[0]);
            buf[n++] = ch;
        }
        else {
            if(jongseong[0]) {
                ch = hangul_choseong_to_cjamo(choseong[0]);
                buf[n++] = ch;
                ch = hangul_jongseong_to_cjamo(jongseong[0]);
                buf[n++] = ch;
            }
            else {
                ch = hangul_choseong_to_cjamo(choseong[0]);
                buf[n++] = ch;
            }
        }
    }
    else {
        if(jungseong[0]) {
            if(jongseong[0]) {
                ch = hangul_jungseong_to_cjamo(jungseong[0]);
                buf[n++] = ch;
                ch = hangul_jongseong_to_cjamo(jongseong[0]);
                buf[n++] = ch;
            }
            else {
                ch = hangul_jungseong_to_cjamo(jungseong[0]);
                buf[n++] = ch;
            }
        }
        else {
            if(jongseong[0]) {
                ch = hangul_jongseong_to_cjamo(jongseong[0]);
                buf[n++] = ch;
            }
            else {
                ; /* have nothing */
            }
        }
    }
    return buf;
}

function
nabi_ic_preedit_insert()
{
    buf = nabi_ic_get_preedit_string();
    user_preedit_insert(buf);
}

function
nabi_ic_preedit_update()
{
    buf = nabi_ic_get_preedit_string();
    user_preedit_update(buf);
}


/* compose table from iiimf-hangul */

var compose_table_default = new Array(
    0x1100, 0x1100, 0x1101, /* chosung kiyeok + kiyeok = ssangkiyeok */
    0x1103, 0x1103, 0x1104,
    0x1107, 0x1107, 0x1108,
    0x1109, 0x1109, 0x110A,
    0x110C, 0x110C, 0x110D,
    0x1169, 0x1161, 0x116A,
    0x1169, 0x1162, 0x116B,
    0x1169, 0x1175, 0x116C,
    0x116E, 0x1165, 0x116F,
    0x116E, 0x1166, 0x1170,
    0x116E, 0x1175, 0x1171,
    0x1173, 0x1175, 0x1174,
    0x11A8, 0x11A8, 0x11A9,
    0x11A8, 0x11BA, 0x11AA,
    0x11AB, 0x11BD, 0x11AC,
    0x11AB, 0x11C2, 0x11AD,
    0x11AF, 0x11A8, 0x11B0,
    0x11AF, 0x11B7, 0x11B1,
    0x11AF, 0x11B8, 0x11B2,
    0x11AF, 0x11BA, 0x11B3,
    0x11AF, 0x11C0, 0x11B4,
    0x11AF, 0x11C1, 0x11B5,
    0x11AF, 0x11C2, 0x11B6,
    0x11B8, 0x11BA, 0x11B9,
    0x11BA, 0x11BA, 0x11BB
);


/* automata.c */

function
hangul_compose(first, last)
{
    var cpr;
    for(cpr in compose_table_default) {
        if(compose_table_default[cpr * 3] == first && compose_table_default[cpr * 3 + 1] == last) {
            return compose_table_default[cpr * 3 + 2];
        }
    }
    return 0;
}

function
nabi_keyboard_mapping(keyval)
{
    return keyboard_map_2[keyval - 0x0021];
}

function
nabi_automata_2(keyval)
{
    var ch;
    ch = nabi_keyboard_mapping(keyval.charCodeAt(0));

    if(jongseong[0]) {
        if(hangul_is_choseong(ch)) {
            jong_ch = hangul_choseong_to_jongseong(ch);
            comp_ch = hangul_compose(jongseong[0], jong_ch);
            if(hangul_is_jongseong(comp_ch)) {
                jongseong[0] = comp_ch;
                nabi_ic_push(comp_ch);
            }
            else {
                nabi_ic_commit();
                choseong[0] = ch;
                nabi_ic_push(ch);
                nabi_ic_preedit_insert();
                return 0;
            }
            nabi_ic_preedit_update();
            return 0;
        }
        if(hangul_is_jungseong(ch)) {
            var pop, peek;
            pop = nabi_ic_pop();
            peek = nabi_ic_peek();

            if(hangul_is_jungseong(peek)) {
                jongseong[0] = 0;
                nabi_ic_commit();
                choseong[0] = hangul_jongseong_to_choseong(pop);
                jungseong[0] = ch;
                nabi_ic_push(choseong[0]);
                nabi_ic_push(ch);
            }
            else {
                var loc_choseong, loc_jongseong;
                ret_arr = hangul_jongseong_dicompose(jongseong[0]);
                loc_jongseong = ret_arr[0];
                loc_choseong = ret_arr[1];
                jongseong[0] = loc_jongseong;
                nabi_ic_commit();
                choseong[0] = loc_choseong;
                jungseong[0] = ch;
                nabi_ic_push(loc_choseong);
                nabi_ic_push(ch);
            }
            nabi_ic_preedit_insert();
            return 0;
        }
    }
    else if(jungseong[0]) {
        if(hangul_is_choseong(ch)) {
            if(choseong[0]) {
                jong_ch = hangul_choseong_to_jongseong(ch);
                if(hangul_is_jongseong(jong_ch)) {
                    jongseong[0] = jong_ch;
                    nabi_ic_push(jong_ch);
                } else {
                    nabi_ic_commit();
                    choseong[0] = ch;
                    nabi_ic_push(ch);
                    nabi_ic_preedit_insert();
                    return 0;
                }
            } else {
                choseong[0] = ch;
                nabi_ic_push(ch);
            }
            nabi_ic_preedit_update();
            return 0;
        }
        if(hangul_is_jungseong(ch)) {
            comp_ch = hangul_compose(jungseong[0], ch);
            if(hangul_is_jungseong(comp_ch)) {
                jungseong[0] = comp_ch;
                nabi_ic_push(comp_ch);
            } else {
                nabi_ic_commit();
                jongseong[0] = ch;
                nabi_ic_push(ch);
                nabi_ic_preedit_insert();
                return 0;
            }
            nabi_ic_preedit_update();
            return 0;
        }
    }
    else if(choseong[0]) {
        if(hangul_is_choseong(ch)) {
            comp_ch = hangul_compose(choseong[0], ch);
            if(hangul_is_choseong(comp_ch)) {
                choseong[0] = comp_ch;
                nabi_ic_push(comp_ch);
            }
            else {
                nabi_ic_commit();
                choseong[0] = ch;
                nabi_ic_push(ch);
                nabi_ic_preedit_insert();
                return 0;
            }
            nabi_ic_preedit_update();
            return 0;
        }
        if(hangul_is_jungseong(ch)) {
            jungseong[0] = ch;
            nabi_ic_push(ch);
            nabi_ic_preedit_update();
            return 0;
        }
    }
    else {
        if(hangul_is_choseong(ch)) {
            choseong[0] = ch;
            nabi_ic_push(ch);
            nabi_ic_preedit_insert();
            return 0;
        }
        else if(hangul_is_jungseong(ch)) {
            jungseong[0] = ch;
            nabi_ic_push(ch);
            nabi_ic_preedit_insert();
            return 0;
        }
    }
    nabi_ic_commit();
    nabi_ic_commit_keyval(keyval);
    return 0;
}


/* debug */

function
debug_output()
{
    alert_str = "OUTPUT\n" +
            "stack[0]: " + stack[0] + "\n" +
            "stack[1]: " + stack[1] + "\n" +
            "stack[2]: " + stack[2] + "\n" +
            "stack[3]: " + stack[3] + "\n" +
            "stack[4]: " + stack[4] + "\n" +
            "stack[5]: " + stack[5] + "\n" +
            "stack[6]: " + stack[6] + "\n" +
            "stack[7]: " + stack[7] + "\n" +
            "stack[8]: " + stack[8] + "\n" +
            "stack[9]: " + stack[9] + "\n" +
            "stack[10]: " + stack[10] + "\n" +
            "stack[11]: " + stack[11] + "\n" +
            "choseong[0]: " + choseong[0] + "\n" +
            "choseong[1]: " + choseong[1] + "\n" +
            "choseong[2]: " + choseong[2] + "\n" +
            "choseong[3]: " + choseong[3] + "\n" +
            "jungseong[0]: " + jungseong[0] + "\n" +
            "jungseong[1]: " + jungseong[1] + "\n" +
            "jungseong[2]: " + jungseong[2] + "\n" +
            "jungseong[3]: " + jungseong[3] + "\n" +
            "jongseong[0]: " + jongseong[0] + "\n" +
            "jongseong[1]: " + jongseong[1] + "\n" +
            "jongseong[2]: " + jongseong[2] + "\n" +
            "jongseong[3]: " + jongseong[3];
    alert(alert_str);
}



////////////////////////////////////////////////////////////// HTML Code

<html>
<head>
<title>Korean input using Nabi on Javascript</title>

<script type="text/javascript" src="nabi.js"></script>
<script type="text/javascript">
var hangul_toggle_char = "`";

function
user_commit(buf)
{
    var ic;
    for(ic in buf)
        document.form1.view.value += String.fromCharCode(buf[ic]);
}

function
user_commit_keyval(keyval)
{
    document.form1.view.value += keyval;
}

function
user_preedit_insert(buf)
{
//    var ic;
//    for(ic in buf)
//        document.write("&#" + buf[ic] + ";");
}

function
user_preedit_update(buf)
{
//    var ic;
//    for(ic in buf)
//        document.write("&#" + buf[ic] + ";");
}

function
convert_text()
{
    var hangul_toggle = 1;
    nabi_ic_buf_clear();
    document.form1.view.value = "";
    textbuf = document.form1.type.value + " ";

    for(i = 0; i < textbuf.length; i++) {
        if(textbuf.charAt(i) == "\r") {
            ; // ignore '\r', already is an '\n'
        }
        else if(textbuf.charAt(i) == hangul_toggle_char)
            (hangul_toggle == 0) ? hangul_toggle = 1 : hangul_toggle = 0;
        else {
            if(hangul_toggle)
                nabi_automata_2(textbuf.charAt(i));
            else
                document.form1.view.value += textbuf.charAt(i);
        }
    }
}

function
change_toggle_char()
{
    hangul_toggle_char = document.form1.toggle.value;
    convert_text();
}
</script>
</head>
<body onLoad="document.form1.type.focus();" style="padding: 20px">
<center>
<font size="+1"><b> Korean input using </b></font>
<font size="+3"><b> Nabi on Javascript </b></font>
<p>This is A simple script that uses <a href="http://nabi.kldp.net">Nabi</a>'s automata code to convert English characters into Korean.<br />

<form name="form1" method="post" action="">
<p><b> To type in English:</b> Text between <input type="text" value="`" size="1" name="toggle" style="border:1px #666 solid; background-color:#fff;" onchange="change_toggle_char();"/> is not converted.</p>

<textarea name="view" rows="10" cols="70" style="border:1px #666 solid; background-color:#eee;"></textarea>
<br />
<br />- type below -<br />
<textarea name="type" rows="5" cols="70" style="border:1px #666 solid; background-color:#fff;"onkeyup="convert_text();"></textarea>
</form>

<br />

<p><b>Nabi on Javascript</b> is based on <a href="http://nabi.kldp.net">Nabi 0.13</a> and you can <a href="nabi.js">download</a>, or <a href="http://nskystars.wozoa.net/temp/projects/nabi/nabi.txt">view</a> the script.<br />The copyright for this code is GPL.</p>

</center>
</body>
</html>

'Web > Javascript' 카테고리의 다른 글

엠베딩 오브젝트를 자동으로 읽어 들이기?(IE패치 때문에)  (0) 2013.09.26
textSlider 스크롤 scroll  (0) 2013.09.26
js용 MD5  (0) 2013.09.26
실시간 보여주기  (0) 2013.09.26
스무스 페이딩  (0) 2013.09.26