2013年7月29日 星期一

中文轉羅馬拼音 完整示範



在製作 中文轉羅馬拼音之前 必須先了解其中的原理!
當我們再輸入 鍵盤同時 將傳送一組 字串
比如說  要將 林哲健 轉成 羅馬拼音

首先收到這組字串 林哲健
在個別將國字 做比對 林=xup6  哲=xup6 健=ru04
再用這組字串 轉換成注音 變成 ㄌ一ㄣˊ  ㄓㄜˊ ㄐㄧㄢˋ
再將注音 正規化 去除 ˇ ˋˊ ˙
 然後 開始比對 注音 將得到羅馬拼音
ㄌ一ㄣ= LIN
ㄓㄜ    =je
ㄐㄧㄢ=Jian

那麼 中文字 10萬多個字 及 很多種比對資料
甚至更多 我們要如何將資料
有效率的存取與調用呢??
這時就 必須使用到 SQL 資料庫

在收集資料 比較痛苦一點
網路上雖然有很多 羅馬拼音 與 注音的 資料表
但是卻很少 英文 與注音 的比對的資料表
這裡可能要辛苦找一下

接下來資料有了 整理成一個 Access檔
 Access檔 裡面有三個 資料表 我大概 講解一下

第一個  字轉Key 有國字 及 鍵盤碼
比如   尺   = t3 建=ru04 帥=gj94

第二個  符號轉注音 有 符號 與 注音
比如    1= ㄅ  Q=ㄆ A=ㄇ

第三個 注音轉拼音  有注音 與 羅馬拼音
比如 ㄌ一ㄣ= LIN    ㄓㄜ =je   ㄐㄧㄢ=Jian

簡單來說 我們只是把 資料 輸入進去 經由 比對 再把結果送出
原理就這麼簡單!!
儘管簡單 收集資料卻很痛苦 不過做完很有成就感  !
開始來看範例吧


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.OleDb;
namespace ChineseToABC
{
    public partial class Frm_Main : Form
    {
        //首先 建立 全域的connection連線物件
        OleDbConnection conn = new OleDbConnection
                (//連線物件+來源
                "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + "中文轉羅馬.accdb"
                );
        //再來 建立 全域性的 SQL查詢指令字串
        string SelectCmd;
        //存放比對結果的字串
        string re = "";// 存放 輸入的英文+符號數字
        string OKGO = "";//存放 注音
        string STAR = "";//存放 羅馬拼音

        public Frm_Main()
        {
            InitializeComponent();
        }

     




來看上列程式碼 一樣 註解 已經 很清楚了!
基於備忘 還是在特別說一次好了
首先!!
程式啟動同時 會先 宣告 全域物件
為了要多次比對字串 為了方便
宣告全域 資料庫connection連線物件 conn
SQL指令需要多次變化也宣告全域selectedCmd
以及 三個 字串 存放 羅馬 注音 與 英文字
如果像是 中文名子三個國字以上
由於資料庫國字是個別處理 全域的字串可以方便累加上去


在事件觸發之前  先講解一下 視窗控制元件 防備忘
三個  label1~3 分別為 1英文字符號 2注音 3羅馬
一個 textbox1 輸入中文用
一個 BUTTON2 觸發用

OK! 假如現在 在 textbox1 中 輸入:林
按下 BUTTON2
來看下列程式碼!

private void button2_Click(object sender, EventArgs e)
        {
            re = "";  //清除上一次使用的字串
            OKGO = "";//清除上一次使用的字串
            STAR = "";//清除上一次使用的字串
            if (textBox1.Text != string.Empty)//判斷是否空直
            {
                GO(textBox1.Text);//呼叫副程式(帶摻數)
            }
            else
            {
                MessageBox.Show("請輸入中文字");
            }
        }
s sss

re okgo star 這些字串 先歸零 因為 上一次 觸發 字串中還殘留 收尋結果
if (textBox1.Text != string.Empty)判斷是否是空值
不是直接呼叫 GO(textBox1.Text)副程式
並且 帶入剛剛在textBox1.Text輸入的中文

再來 來看 GO() 副程式 如何運作

private void GO(string x)
        {
            for (int i = 0; i <= x.Length - 1; i++)
            {
                conn.Open();//開啟資料庫
                //string SelectCmd2="Select*form 注音轉符號 Whrer 符號='"++"'";
                SelectCmd = "Select*from 字轉KEY Where 字='" + x[i] + "'";//設定查詢語法並加入輸入的中文x
                //將查詢x那一列的所有資料
                OleDbCommand Cmd = new OleDbCommand(SelectCmd, conn);//建立命令加入 語法+連線物件
                OleDbDataReader reader = Cmd.ExecuteReader();//ExecuteReader()是將Command查詢語法傳入connection中
                while (reader.Read())
                //OleDbDataReader 的預設位置在第一個資料錄之前。因此,您必須呼叫 Read 以開始存取任何資料。
                {
                    re += reader["欄位2"].ToString()+"  ";
                    TOTO(reader["欄位2"].ToString());
                }
                label1.Text = "你輸入的KEY是:" + re;
                conn.Close();
            }
        }


來看GO(string x)中的x
是剛剛輸入的textBox1.Text
而第一個 for (int i = 0; i <= x.Length - 1; i++)
是要來判斷 幾個國字 方便 個別搜尋資料庫 假設只有一個字"林"
conn.Open();
再來開啟在全域宣告的資料庫
SelectCmd = "Select*from 字轉KEY Where 字='" + x[i] + "'";
將x[0] 帶入 查詢第一個字 假設是"林"

OleDbCommand Cmd = new OleDbCommand(SelectCmd, conn)
建立命令物件  他需要 命令物件+連線物件

OleDbDataReader reader = Cmd.ExecuteReader()
再來將 命令 傳送給 連線物件 再指派給OleDbDataReader 讀取用

while (reader.Read())
                {
                    re += reader["欄位2"].ToString()+"  ";
                    TOTO(reader["欄位2"].ToString());
                }

reader.Read此方法 為 是否讀取到資料   裡面有資料將回傳 true
re是將 查詢到的資料 的隔壁叫(欄位2)裡的值放入re中
欄位一是:"林" 欄位二是: "XUP6"
而 (累加)+= 是因為 如果 有1個字以上 將會累加到re上
最後再把re 給label!!

再來 TOTO(reader["欄位2"].ToString()); 將查詢結果
再次呼叫副程式!
而本程式週期 因再次呼叫了 副程式
所以要等TOTO()執行完回傳 數據
才能將 此區塊結束!!

注意喔!! 此區況 尚未結束 所以
label1.Text = "你輸入的KEY是:" + re;
                conn.Close(); 
這部分 都尚未執行!!

再來我們來看TOTO()中 做了甚麼處理
我們知道TOTO(reader["欄位2"].ToString());
帶入的參數 是一組 林的 "XUP6" key碼
而在TOTO() 裡面只是將 key轉成 注音 而已
來看下列程式碼!

private void TOTO(string s)
        {
            string yy = "";
            char[] arr = s.ToCharArray(0, s.Length);
            foreach (char c in arr)
            {
                SelectCmd="Select*from 注音轉符號 Where 符號='"+c+"'";
                OleDbCommand Cmd = new OleDbCommand(SelectCmd, conn);
                OleDbDataReader reader = Cmd.ExecuteReader();
                while (reader.Read())
                {
                    yy += reader["注音"];
                }
            }
            OKGO += yy+"  ";
            label2.Text = "你輸入的注音是:" + OKGO;
            end(yy);

        }





來看 TOTO(string s)
"s"是剛剛傳入的 "XUP6"
再來為了將每一個字元做 資料庫獨立搜尋
我們利用ToCharArray 將字串 放進 char[]陣列中
s.ToCharArray(0, s.Length);
s是字串0是起始位置 S.Length是 s字串長度
然後轉成char

然後 再利用foreach (char c in arr)
將arr[]陣列 放進c
在來 foreach區塊內
修改全域的SQL指令 SelectCmd  將c套入指令中!
SelectCmd="Select*from 注音轉符號 Where 符號='"+c+"'";
再來 建立OleDbCommand 和 OleDbDataReader
OleDbCommand Cmd = new OleDbCommand(SelectCmd, conn);
OleDbDataReader reader = Cmd.ExecuteReader();

然後一樣 reader.Read() =true 啟動!
while (reader.Read())
{
yy += reader["注音"];
}

然後在foreach區塊內 C[]會不斷變化
使得while區塊內的yy會不斷累加!!
直到 將字元完整收巡完畢 才跳出區塊
來看剩下的程式碼
OKGO += yy+" ";
label2.Text = "你輸入的注音是:" + OKGO;
end(yy);

將查詢結果 累加OKGO 
為何累加?  因為 TOTO(string s)只將一子字轉成注音
等等還會有第二個字 第三個字 送入這TOTO()
全域的OKGO 將會 把結果累加成一個完整的 名子
label2 將答案顯示
end(yy) 將注音 傳送給!第三個副程式
再來我們來看看end(yy) 中的程式碼
是如何轉 羅馬拼音的


private void end(string er)
        {
            string pattern = "[ˇˋˊ˙]";//把ˇˋˊ˙濾掉
            string replacement = "";//如果找到ˇˋˊ˙替代成空字元
            Regex rgx = new Regex(pattern);//建立正規化 套入pattern過濾條件
            string result = rgx.Replace(er, replacement);//er是注音result是已將ˇˋˊ˙濾掉的字串

            SelectCmd = "Select*from 注音轉拼音 Where 注音='" + result + "'";
            OleDbCommand Cmd = new OleDbCommand(SelectCmd, conn);
            OleDbDataReader reader = Cmd.ExecuteReader();
            while (reader.Read())
            {
                STAR += reader["羅馬拼音1"]+"  ";
            }
            label3.Text = "轉羅馬的英文是:" + STAR;
        }


sas as a

string er是上一個副程式 所搜尋的結果 是注音
但是 資料庫中 比對的注音 並無ˇˋˊ˙
所以我們在這邊需要用到一個 過濾方法
叫做 正規化
原理是將 ㄌ一ㄣˊ 轉成 ㄌ一ㄣ
然後再比對資料庫
此 副程式 只有多了正規化 其他都 大同小異
後續不做介紹
此程式結束後 將 遞迴到GO()
而TOTO()已經運算結果回傳完畢 跳出區塊
關閉資料庫 CONN.CLOSE
在跳出 FOR迴圈
如果FOR迴圈中的X還有其他字元 將會在執行一次上續動作
private void GO(string x)
{
for (int i = 0; i <= x.Length - 1; i++)

直到i=字元長度 中指for迴圈



完!

2 則留言:

  1. 您好, 我因為工作上的需要, 要將國字轉換成鍵盤碼, 想請問您是否可以提供您的Access檔給我做測試? 或是否可以告知可以到哪邊搜尋到相關資料表? 非常感謝!

    回覆刪除
    回覆
    1. 抱歉,資料我已經刪掉了,我相信這不難找,你可以在中文轉羅馬拼音的網站上找到,祝你順利

      刪除