C# 解決文字方塊輸入surrogate 字元(如 CJK 擴充字集字元長度為 2 的漢字)的問題

因為 textBox 的 TextChanged 事件,會引發2次 KeyDown事件,故字元長度為2的字在程式碼執行中其實會「輸入」2次。如何正確判斷字元長度 2的 surrogate字元已完全輸入完畢呢?以下是末學的解決方法。

在C# 中,只有在 TextChanged事件有此問題,若是比對或操作已經輸入完成的字元,則surrogate字元並不會造成任何障礙。也就是說如 IndexOf() 的方法,不論是在surrogate字元或非surrogate字元的操作,都不會造成問題,唯獨在TextChanged事件中判斷時會有所影響。此問題應該係 TextChanged事件尚未跟上surrogate字元的腳步,猶如目前在MS Access作篩選與查詢的判斷時,一樣會出錯。





int surrogate = 0;
bool isKeyDownSurrogate(string x)
{/*解決輸入CJK字元長度為2的字串問題 https://docs.microsoft.com/en-us/previous-versions/windows/desktop/indexsrv/surrogate-pairs
  * 
https://stackoverflow.com/questions/50180815/is-string-replacestring-string-unicode-safe-in-regards-to-surrogate-pairs */
    UnicodeCategory category = UnicodeCategory.Surrogate;//https://docs.microsoft.com/zh-tw/dotnet/api/system.globalization.unicodecategory?view=net-6.0
    char[] xChar = x.ToArray();
    foreach (char item in xChar)
    {
        //if (CharUnicodeInfo.GetUnicodeCategory(item) == category)
        if (Char.IsSurrogate(item))
        {
            surrogate++;
        }
    }
    if (surrogate % 2 != 0) { surrogate = 0; return true; }
    else { surrogate = 0; return false; }
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
    string x = textBox2.Text, x1 = textBox1.Text;
    if (x == "" || x1 == "") return;
    if (isKeyDownSurrogate(x)) return;//surrogate字在文字方塊輸入時會引發2次keyDown事件
    var sa = findWord(x, x1);
    if (sa == null) return;
    int s = sa[0], nextS = sa[1];
    if (s > -1)
    {
        textBox1.Select(s, x.Length);
        textBox1.ScrollToCaret();
        if (nextS > -1) { textBox2.BackColor = Color.Yellow; doNotLeaveTextBox2 = false; return; }
    }
    else
    {
        textBox2.BackColor = Color.Red;
        doNotLeaveTextBox2 = false; return;
    }
    textBox2.BackColor = Color.GreenYellow;
    SystemSounds.Hand.Play();//文本唯一提示
    doNotLeaveTextBox2 = true;
    textBox2.SelectAll();

}

int[] findWord(string x, string x1)
{
    if (x == "" || x1 == "") return null;
    int s, nextS;
    s = x1.IndexOf(x);
    nextS = x1.IndexOf(x, s + x.Length);
    return new int[] { s, nextS };
}
全部程式碼見:https://github.com/oscarsun72/TextForCtext/blob/170f06a2cca8789cb7c1e672d18929e96af016dd/WindowsFormsApp1/Form1.cs#L1288

留言

熱門文章