none
如何取得在 textBox 正在輸入的CJK擴充字集漢字字串長度(.Text 屬性和TextChanged事件之運用) RRS feed

  • 問題

  • CJK擴充字集B以後的漢字多是2個字元長度,往往造成判斷字長的困難。末學稍為搜尋,好像尚無此題,故來發問。

    末學是用「𬗨」(倉頡碼:vfpbc,這是擴充E的字)等字來測試的。各位菩薩可以用此字來測試看看,能否在鍵盤在textbox 上輸入此字時,在TextChanged事件正確抓到「𬗨」這個字的長度,乃至其值。(不能用貼上的,要用輸入法輸入喔)

    在System.Globalization下有 StringInfo 物件可供利用,然而在textBox 輸入字元長為2的漢字時,在TextChanged事件捕捉到的,卻會先是這種漢字的第一個字元,即HighSurrogate,然後才是第二個(LowSurrogate)。末學用逐行執行的方式偵錯才發現的。等於是在鍵盤輸入到textBox的時候,雖似輸入一個漢字,實則是輸入了二次,(二個字元,先是HighSurrogate,後是LowSurrogate),在LowSurrogate輸入時會引發 Form1_KeyDown事件。且在這事件發生後(LowSurrogate輸入完成後)才能捕捉到正確的漢字長度=1(LengthInTextElements=1)。因此,若末學將檢查字長的判斷寫在 TextChanged事件內,卻沒有加以判斷它是否為Surrogate此類字時,就將此判斷字長的方法傳回值=1當作一個「字」,就新增此字到資料庫去,那麼就會誤存成HighSurrogate,而不是正確的漢字了。

    很奇怪的是,明明有這個LengthInTextElements屬性可以判斷字長,可是當2個字元長的Surrogate的字被誤切成一個一個不完整時,這個LengthInTextElements仍然誤判作一個字長。

    末學想到的,是利用IsSurrogatePair()IsHighSurrogater() 來判斷,如下式;不知先進們有沒有更簡易且適當的方法來正確判斷在textbox上輸入的漢字,是否恰是一個字長

    此外,除了 TextChanged 事件可供利用外,有沒有別的事件可供判斷使用者輸入之資料是否合格的時機呢?

    感恩感恩各位先進菩薩慈悲指教了 南無阿彌陀佛

    • 作業系統版本:Windows10
    • 開發工具版本-Visual Studio 2017 Community
    • 開發環境-Windows Form

    private void textBox2_TextChanged(object sender, EventArgs e) { if (Char.IsSurrogatePair(textBox2.Text,0)) { if (wordLength(textBox2.Text) != 1) { MessageBox.Show("只能是一個字!"); return; } } else { if (!Char.IsHighSurrogate(Convert.ToChar(textBox2.Text)))//https://msdn.microsoft.com/zh-tw/library/xcwwfbb8(v=vs.110).aspx //if (Char.IsSurrogatePair(Convert.ToChar(textBox2.Text))) { if (wordLength(textBox2.Text) != 1) { MessageBox.Show("只能是一個字!"); return; } } else { return; } } editRecord();//這是要增此字入資料庫的方法 textBox2.SelectAll();//全選方塊內的文字,方便連續一個字一個字地輸入 }

     int wordLength(string w)

            {
                StringInfo si = new StringInfo(w);
                return si.LengthInTextElements;
            }

     void editRecord()
            {
                ado.Recordset rst = new ado.Recordset();
                rst.Open(@"select 字,命名筆畫,命名筆畫驗算過,取名字 from 字 where strcomp(字,""" + textBox2.Text + @""")=0", Cnt, ado.CursorTypeEnum.adOpenKeyset, ado.LockTypeEnum.adLockOptimistic);
                if (rst.RecordCount > 0)
                {
                    if (rst.Fields["命名筆畫驗算過"].Value)
                    {
                        if (MessageBox.Show("大菩薩,「" + textBox2.Text + "」字已驗算過!確定更改?筆畫為" + Convert.ToString(rst.Fields["命名筆畫"].Value) + "\n南無阿彌陀佛", "watch out!!", MessageBoxButtons.OKCancel,MessageBoxIcon.Exclamation,MessageBoxDefaultButton.Button2)==DialogResult.Cancel)
                        {
                            return;
                        }
                    }
                    if (Convert.ToInt32( rst.Fields["命名筆畫"].Value)!=Int32.Parse( textBox1.Text))
                    {
                        if (MessageBox.Show("大菩薩,「"+textBox2.Text +  "」原擬定的筆畫為" + Convert.ToString(rst.Fields["命名筆畫"].Value)+ "!確定更改? \n南無阿彌陀佛", "watch out!! ", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Cancel)
                        {
                            return;
                        }
                    }
                    rst.Fields["命名筆畫"].Value = textBox1.Text;
                    rst.Fields["命名筆畫驗算過"].Value = -1;
                    rst.Fields["取名字"].Value = -1;
                    rst.Update();
                }
                else
                {
                    rst.AddNew();
                    rst.Fields["字"].Value = textBox2.Text;
                    rst.Fields["命名筆畫"].Value = textBox1.Text;
                    rst.Fields["命名筆畫驗算過"].Value = -1;
                    rst.Fields["取名字"].Value = -1;
                    MessageBox.Show("記得輸入部首!南無阿彌陀佛","缺部首!",MessageBoxButtons.OK,MessageBoxIcon.Information);
                    comboBox1.Focus();
                    comboBox1.BackColor = Color.Yellow;
                    rst.Update();
                }
                rst.Close();
                return;
            }



    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?






    <link href="moz-extension://ca57c392-8d2a-44cf-88fa-6ea7c8794c92/skin/s3gt_tooltip_mini.css" rel="stylesheet" type="text/css" /><style media="print" type="text/css">#s3gt_translate_tooltip_mini { display: none !important; }</style>

    • 已編輯 任真 2018年5月8日 上午 05:27 排版
    2018年5月7日 下午 01:27

解答

  • 目前末學的解決方案:

    原理是抓到在輸入2字元以上長度時(如末學所用小小輸入法亦可將詞當字輸入,故可一次輸入好幾字)此情形,如同surrogate字其實是一次輸入了二個字元;也就是一個字元輸入會觸發一次TextChanged事件。等於是暗地裡自行在跑迴圈。掌握了這一原則,善用Length屬性如下作判斷。

    只是仍舊不知道除了 TextChanged 事件外,還沒有什麼可以供我們判斷使用者輸入事件的時機?還盼各位大德先進門賜教了 感恩感恩  南無阿彌陀佛

    private void textBox2_TextChanged(object sender, EventArgs e)
            {
                string txtStr= textBox2.Text;
                //檢查空值與英數
                if (textBox1.Text == "")
                {
                    MessageBox.Show("請輸入筆畫\n南無阿彌陀佛"); 
                    return;
                }
                if (!Is_Number(textBox1.Text) || textBox2.Text.Trim() == "" || textBox1.Text == "")
                {
                    return;
                }
                if (IsNatural_Number(txtStr))
                {
                    MessageBox.Show("大菩薩,請您輸入中文字!\n 南無阿彌陀佛");
                    return;
                }
    
                //檢查中文字長及符號  
                if (txtStr.Length==1)
                {                
                    if (CheckInputText.IsSymbols(Convert.ToChar(txtStr)))
                    {
                        MessageBox.Show("大菩薩,請您輸入中文字!\n 南無阿彌陀佛");
                        return;
                    }
                    //以下開始檢查中文字長
                    if (char.IsHighSurrogate(Convert.ToChar( txtStr)))
                    {
                        return;//如果是surrogate的字就進入第2個迴圈
                    }
                    else
                    {
                        editRecord( txtStr);
                    }
                }
                else
                {
                    if (wordLength(txtStr) > 1)
                    {
                        MessageBox.Show("阿彌陀佛 只能是一個字!\n感恩感恩 南無阿彌陀佛", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    else
                    {
                        editRecord(txtStr);
                    }
                }
            }

    感恩感恩 南無阿彌陀佛


    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?





    • 已標示為解答 任真 2018年5月15日 下午 12:54
    • 已編輯 任真 2018年5月15日 下午 01:14
    2018年5月15日 下午 12:50

所有回覆

  • [測試記錄] UTF32 位元組數與 Char 型別~

    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2018年5月7日 下午 05:13
  • .NET平台採用Unicode字元集, 所以應該可以不需要再使用CJK擴充字集了
    2018年5月8日 上午 12:26
  • 謝謝 tihs菩薩指教。Unicode字元集裡就是包括了CJK擴充字集在內吧。CJK擴充字集即Unicode字元集裡的一部分,當然要用到囉。CJK擴充字集主要是收一些罕用漢字,參見;自B區以後,多是2個字元長度的漢字。要輸入或儲存這樣的資料來使用,勢必要精確計算所含字的長度,才不會誤切到字,成為亂碼。末學曾與陳明照菩薩討論過,正好陳菩薩提到的也是「.NET 開發支援Unicode應用程式的可能陷阱」與菩薩您同。而這次主要是在輸入textBox時發現這樣的問題,所以來求教於方家。感恩菩薩不棄指教。感恩感恩 南無阿彌陀佛

    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?


    • 已編輯 任真 2018年5月8日 上午 04:42 改錯
    • 已標示為解答 任真 2018年5月8日 上午 10:34
    • 已取消標示為解答 任真 2018年5月8日 上午 10:34
    2018年5月8日 上午 04:28
  • 感謝心冷菩薩的回覆。璉菩薩在那裡好像也沒有解法,特別是在textBox輸入時,正確抓到字串長度及其值的方法。末學即曾注意Docs裡這些關於Char的文件了,才會知道有「Surrogate」這類的文字字串存在。但願有大菩薩能開示除了末學此處所解之外的解法。畢竟末學只是門外漢,半摸索、半牽就的,當不地道,自誤誤人吶。若真沒有高手指教,難道末學這種拙鈍的程式碼是唯一的正解嗎?末學實不敢信也。感恩感恩 南無阿彌陀佛

    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?


    • 已編輯 任真 2018年5月15日 下午 07:43
    2018年5月8日 上午 04:35
  • 從那篇可以猜想的作法是將所有字串轉換為 UTF32 ,再按 4 bytes 一字元來計算長度跟切割,切完後再轉回 Unicode 。

    https://msdn.microsoft.com/zh-tw/library/system.text.encoding.utf32.aspx


    不精確的問法,就會得到隨便猜的答案;自己都不肯花時間好好描述問題,又何必期望網友會認真回答?

    2018年5月8日 下午 03:48
  • 感謝心冷兄。我想菩薩您可能還沒會過我的意思,大概是自己表達還不夠清楚。

    末學的意思是在文字方塊上輸入時,在TextChange事件發生時,如何捕捉到正確的字長。也是因為如此,末學才發現輸入一個字串長度為2的漢字,其實在TextChange事件中好像會引發兩次Form1_KeyDown事件,也就是這2個字長不是同時輸入的,而是分前後、一個一個輸入的(即便我們只輸入了一次、一個漢字)。您提供的好像是已經輸入完了的判斷方法;也正是末學想知道的,除了TextChange事件外,有沒有別的事件可以寫上如此的判斷式。因為TextChange是在任何輸入發生的同時發生的,與一般輸入完再進行判斷有所不同。末學也不知道目前在C# Windows.Form裡有沒有類似MS Access AfterUpdate的事件可供利用,這樣在輸入完時再判斷,或許較簡單些了。只是AfterUpdate事件也得伴隨著焦點離開控制項才會發生,而末學傾向於是在不離開控制項的同時,能夠不斷連續的輸入單字,同時也不斷連續地判斷字長,以便驗證,存入資料庫資料表中,這樣來提昇輸入漢字至資料庫資料表的效率。

    末學是用「𬗨」(倉頡碼:vfpbc,這是擴充E的字)等字來測試的。菩薩可以用此字來測試看看,能否在鍵盤在textbox 上輸入此字時,在TextChanged事件正確抓到「𬗨」這個字的長度,乃至其值。(不能用貼上的,要用輸入法輸入才行)

    您提供的寶貴方法,陳明照先生好像就試過了。末學得空也得來好好了解熟悉一般。感恩您了。阿彌陀佛


    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?


    • 已編輯 任真 2018年5月10日 上午 10:48 補充
    2018年5月10日 上午 10:44
  • 目前末學的解決方案:

    原理是抓到在輸入2字元以上長度時(如末學所用小小輸入法亦可將詞當字輸入,故可一次輸入好幾字)此情形,如同surrogate字其實是一次輸入了二個字元;也就是一個字元輸入會觸發一次TextChanged事件。等於是暗地裡自行在跑迴圈。掌握了這一原則,善用Length屬性如下作判斷。

    只是仍舊不知道除了 TextChanged 事件外,還沒有什麼可以供我們判斷使用者輸入事件的時機?還盼各位大德先進門賜教了 感恩感恩  南無阿彌陀佛

    private void textBox2_TextChanged(object sender, EventArgs e)
            {
                string txtStr= textBox2.Text;
                //檢查空值與英數
                if (textBox1.Text == "")
                {
                    MessageBox.Show("請輸入筆畫\n南無阿彌陀佛"); 
                    return;
                }
                if (!Is_Number(textBox1.Text) || textBox2.Text.Trim() == "" || textBox1.Text == "")
                {
                    return;
                }
                if (IsNatural_Number(txtStr))
                {
                    MessageBox.Show("大菩薩,請您輸入中文字!\n 南無阿彌陀佛");
                    return;
                }
    
                //檢查中文字長及符號  
                if (txtStr.Length==1)
                {                
                    if (CheckInputText.IsSymbols(Convert.ToChar(txtStr)))
                    {
                        MessageBox.Show("大菩薩,請您輸入中文字!\n 南無阿彌陀佛");
                        return;
                    }
                    //以下開始檢查中文字長
                    if (char.IsHighSurrogate(Convert.ToChar( txtStr)))
                    {
                        return;//如果是surrogate的字就進入第2個迴圈
                    }
                    else
                    {
                        editRecord( txtStr);
                    }
                }
                else
                {
                    if (wordLength(txtStr) > 1)
                    {
                        MessageBox.Show("阿彌陀佛 只能是一個字!\n感恩感恩 南無阿彌陀佛", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return;
                    }
                    else
                    {
                        editRecord(txtStr);
                    }
                }
            }

    感恩感恩 南無阿彌陀佛


    天豈去此哉,任真無所先. 如有周公之才之美,使驕且吝,其餘不足觀也矣. 雖多,亦奚以為?





    • 已標示為解答 任真 2018年5月15日 下午 12:54
    • 已編輯 任真 2018年5月15日 下午 01:14
    2018年5月15日 下午 12:50