漢字長度處理_CJK擴充字集正確處理探賾

緒言

CJK擴充字集後,漢字在計算機裡的Len()長度,就有了1單位長和2單位長的區別,不知日後有沒有比2還長的了。(我這所謂一單位長大概就是用了2Byte吧,2單位長就是4Byte
在VBA乃至VB中的文字相關函式,好像只剩VBA.StrComp()還能正常作用。連Access資料庫檔在作資料表索引及查詢關聯(資料庫關聯)、篩選、排序時,都會出錯。
因此,如何取得正確的中文字元長度,一直是個大問題、大困擾。似乎專家也尚無周全之法。
但在與陳菩薩耐心地討論與被指導且自導後,發現好像露了一線曙光。

StringInfo 物件

在VB與C#裡都有的 StringInfo 物件
其緣起始末詳於此留下足跡,日後再有進展,再於此帖裡反映了。感恩感恩。南無阿彌陀佛


孫守真2017年6月19日 下午5:09:00
陳菩薩您好,剛才末學看到這段(搜尋時意外發現的)且文章很新:(2017/4/11;英文版竟然還比較新呢5/31/2017,可見中文版還來不及同步吧。
字串的 屬性代表它包含的 Char 物件數目,而非 Unicode 字元的數目。 若要存取字串中的個別 Unicode 字碼指標,請使用 物件。
https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/strings/
是否目前C# 已提供了「個別 Unicode 字碼指標」的解決方法?這個「 Unicode 字碼指標」的「StringInfo 物件」是否便能方便我們正確判讀包括CJK擴充字集在內的一切漢字了? 感恩感恩 南無阿彌陀佛
哈 我剛試著把網址裡zh-tw改成en-us才發現,原來中文版格式上錯了,才會出現
原文是:
The Length property of a string represents the number of Char objects it contains, not the number of Unicode characters. To access the individual Unicode code points in a string, use the StringInfo object.
(原來zh-tw的中文譯成「字碼指標code points,就是「碼位」或「碼點」嘛。)
這「StringInfo」object是否是一個新的類別(class)呢?對我們現下討論的主題,有沒有幫助呢?
https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo?view=netframework-4.7
我剛讀到一篇說C語言裡並沒有字串型態的變數,是否這個string也是C#新加入的成員呢?還是只是object並不是變數型態?
http://dhcp.tcgs.tc.edu.tw/c/p009.htm
再查了一下,其實VS 2008 好像就有了
StringInfo.SubstringByTextElements 方法 (Int32)
https://msdn.microsoft.com/zh-tw/library/bx3zb6dh(v=vs.110).aspx
其中這句「The zero-based index of a text element in this StringInfo object.」好像就是類似Characters這樣集合類型的物件了;也是從索引值0開始的。
Characters這個屬性,恐怕不只Word有,我用它來google發現別的好像也有用到。
先生擷取中文字串長度的方法,在需要逐字處理中文字時,或許還可行,但若有類似Characters這樣,能正確載入中文字元的集合,則逐一取出處理,似更方便了。
用先生的方法,恐怕仍須配合類似 VBA.Mid()這樣的函式逐一取出中文字元再來處理才行,就不若
For Each char in Characters 
…… 
Next char 
這樣的迴圈處理來得便捷穩當了。所以才想這個Characters的集合到底是憑什麼本事可以正確擷取到一串字串中的各個中文字元也。

剛才發現,其實
StringInfo.SubstringByTextElements 方法 (Int32, Int32)
就類似VBA的Mid()函式了嘛。
應該是從StringInfo物件這裡擷取中文字串或判斷中文字長度,而不是從String物件下,菩薩您沒提到StringInfo而只提到String;是否蹊蹺就在這個point上呢?還望菩薩您慈悲救度了。感恩感恩。
StringInfo的namespace是System.Globalization
String.Substring的則是System
可見是二個物件類別;可能是菩薩您沒有留意有這個StringInfo物件可用,是否?但願這解了咱們共有的燃眉之急啊。末學還不能實測,只能如此演繹想當然爾了。還請菩薩您撥冗定奪示下。感恩感恩。阿彌陀佛
剛才略看了一下它的示例,其實VB也可以操作。且C#好像用Console來試算也不難,我晚會兒再試看看。玩 hello world讓我大概知道怎麼寫類似的C#小程序了。
https://msdn.microsoft.com/zh-tw/library/aka44szs(v=vs.110).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2
https://www.microsoft.com/net/tutorials/csharp/getting-started/hello-world

另順帶一提:得先生用心的回覆,末學內心已有個譜了,大概就是以微軟的教程及網路相關資訊為主來自修入門先了。如上報告,可見一斑吧。感恩菩薩。南無阿彌陀佛


原來,我們所需要的,都在這個namespace裡了:

System.​Globalization Namespace

The System.Globalization namespace contains classes that define culture-related information, including language, country/region, calendars in use, format patterns for dates, currency, and numbers, and sort order for strings. These classes are useful for writing globalized (internationalized) applications. Classes such as StringInfo and TextInfoprovide advanced globalization functionalities, including surrogate support and text element processing.



Text​Info Class



成功了一半(漢字字元長度正確取得了)

哈哈 果然解決菩薩您的心頭之患了吧 感恩感恩 末學也堪略報您熱心指引之一二了。
果然「蹊蹺」就在 StringInfo Object 上,魔鬼就藏在這個「System.Globalization」細節裡,所幸「但願這解了咱們共有的燃眉之急啊」一語成讖了 ^_^ 感恩感恩 南無阿彌陀佛

末學也深有同感,有時程式難構思,就在不知道可用的物件、屬性、方法有哪些,放哪裡呢!這幾天踏破鐵鞋、想破頭腦,就是聚焦在這上頭……,終於皇天不負苦心人了。感恩感恩。

剛才才發現先生已回應了,而我方靠自己的土法來煉鋼,用了人家的示例寫了這麼一段,成功了,只可惜Console不支援擴充字集,故未能正常印出該字,在VB下我還知用Debug.print來列出,不知在C#有沒有替代的方法。剛才再試著跑,我寫的這個後半部分的條列式似乎還是錯的

using System;
using System.Globalization;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            
            
            //string  mystr;
            string str = "𧖟厵陳𣡻明𨰻";
            //string str = ActiveDocument.Range.Text
            StringInfo mystrInof = new System.Globalization.StringInfo(str);            
            Console.WriteLine(str.Length);
            Console.WriteLine(mystrInof.LengthInTextElements);                
            
            
            TextElementEnumerator mystrEnum = StringInfo.GetTextElementEnumerator(str);
            while (mystrEnum.MoveNext())
            {                   
                    string mystr = mystrEnum.Current.ToString();
                   Console.WriteLine(mystr);
                   
            }
            Console.ReadLine();
            //StringInfo.SubstringByTextElements(int);
            //System.Globalization.StringInfo.SubstringByTextElements(int, int)
            //Console.WriteLine("Hello World!");
            
        }
    }
}
前半段是測長度
後半段是逐一列舉(即已類似Characters的應用了 南無阿彌陀佛)但似尚未成功。擬改寫成VB,用Debug.Print或 Word.Document.Range 來列舉出看看。

前半我主要是看到這篇,照他的寫法改寫試成的

參考之文件,均蒐集於此,也便菩薩您參考



剛才用WebSite檢驗(新網站),我之前寫的是正確的,只是Console(主控台)無法支援字元,故顯示似不正確爾。程式碼略改如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //string mystr;
        string str = "𧖟厵陳𣡻明𨰻";
        //string str = ActiveDocument.Range.Text
        StringInfo mystrInof = new System.Globalization.StringInfo(str);
        //Response.Write(str.Length);
        //Response.Write(mystrInof.LengthInTextElements);


        TextElementEnumerator mystrEnum = StringInfo.GetTextElementEnumerator(str);
        while (mystrEnum.MoveNext())
        {
            //string mystr = mystrEnum.Current.ToString();
            //Response.Write(mystr);
            Response.Write(mystrEnum.Current);

        }
        
        //StringInfo.SubstringByTextElements(int);
        //System.Globalization.StringInfo.SubstringByTextElements(int, int)
        //Console.WriteLine("Hello World!");

        ////Response.Write("南無阿彌陀佛");
        ////Response.Write( " " + "南無阿彌陀佛");
        //StringInfo mystrInfo = new StringInfo("南無阿彌陀佛");
        //Response.Write(mystrInfo.SubstringByTextElements(​0, 2));
    }
}
這就是逐一條列,也就是能逐一處理漢字的程式了。

緣起:


留言

熱門文章