如何判断汉字所属的字符集!??(200分)

  • 主题发起人 主题发起人 quzl
  • 开始时间 开始时间
Q

quzl

Unregistered / Unconfirmed
GUEST, unregistred user!
[8D]

如何判断一个汉字所属的字符集!如属 如BIG5码还是属于GB码!
 
判斷一個字是否為 BIG-5 中文字?
請問要判斷連續的兩個 byte是否為一個 BIG-5 中文字,

問此想問看看有沒有現成的 API 或 function 可以用呀?

假如沒有中文應用組件的朋友, Win32 中有一個 IsDBCSLeadByte 這個 API 可用, 在 Delphi 的使用示例如下:

Windows.IsDBCSLeadByte(byte(sTest[1]));

(中文應用組件中的 IsLeadByte 其實也只是呼叫這個 API 而已)

就連是不是中文字這樣簡單的問題可能都並不單純喔...., 這個問題之前被我想得有點鑽牛à尖了.... 也許原發問者寬達可以將 C 的程式借我看一下... :p

先來看這個例子:

procedure TForm1.Button5Click(Sender: TObject);
var
sTest: string;
begin
sTest := '中文字';
// 沒有應用組件的請用這個: Windows.IsDBCSLeadByte(byte(sTest[1]));
if IsLeadByte(@sTest[1]) then ShowMessage('Yes 1');
if IsLeadByte(@sTest[2]) then ShowMessage('Yes 2 ???');
end;
Yes1 顯示出來是對的, 可是 Yes2 也跑出來, 就..., 看來, 這個IsDBCSLeadByte可能只比對了一下內碼表就給結果了. 所以, 以下的程式:

procedure TForm1.Button1Click(Sender: TObject);
var
s: string;
i: integer;
begin
s := '中文字';
for i := 1 to Length(s) do
if Windows.IsDBCSLeadByte(byte(s)) then
ShowMessage(IntToStr(i) + '*' + IntToStr(Ord(s)));
end;
1. 2. 3. 4. 5. 都是 Leadbyte, 連 TrailByte 也是..., 哈哈!

當然, 這牽到中文字是 double-byte, 既然只判斷一個位置不準, 就有人利用兩個字元指標, 除了本身之外, 還比較參考另一個位置的字元, 然後得出一個比較準確的結果. 有興趣的朋友可以參考中文應用組件的以下兩個函數:

function IsMBSLead( p1, p2: pchar ) : Boolean;
function IsMBSTrail( p1, p2: pchar ) : Boolean;
它們可能比較準一些.

大家可能曾注意過, Windows 95 的 EditBox 並無法以滑鼠對半個中文字作出反白選擇標記, 所以, 我自以為找到一個很慢但準確的方法, 可是以下的情形呢?

procedure TForm1.Button2Click(Sender: TObject);
{$h-}
var
sTest: string;
begin
sTest := '中文字';
ShowMessage(Copy(sTest, 2, 2));
with TEdit.Create(Self) do
begin
Parent := Self;
// Text := Copy(sTest, 2, 2); // 1. 中?? bug
Text := sTest[2] + sTest[3]; // 2. 中?? bug
// 不要懷疑, TrailByte + 另一個字的 Leadbyte 正好是 '中'
// 不是 Copy 函數有問題
SelStart := 0;
SelLength := 2;
if SelLength = 0 then ShowMessage('Not Chinese')
else ShowMessage('Yes, Chinese word');
Free;
end;
end;
沒錯啦! 結果是'中'字, 判斷'中'字是中文字也對, 但是各拆一個字的前後出來組出來的結果再判斷其一個字元是不是Leadbyte, 簡直是GIGO (Garbage In Garbage Out)的典型.

說了半天, 問題被我複雜化了, 簡單的說,

1. IsDBCSLeadByte 不是一可完全可靠的函數, 中文是 double-byte, 只以一個傳入字元值作判斷常常不準.
2. 要正確將各個中文字斷開的程式可能很複雜. 用兩個 pchar 來作比較, 準確性會提高一點.

只是提高一點而已, 有中文應用組件的朋友可以試試:

var
sOrigin, sTest: string;
begin
sOrigin := '中文字';
sTest := Copy(sOrigin, 4, 2); // 變成 憒 這個怪字
if IsMBSLead(@sTest[1], @sTest[1]) then Showmessage('Leadbyte');
end;
對的, 我又故意切開中文, 所以有人會講, 應該是 Copy(..., 3, 2)才是, 嗯! ê我怎麼知道該從哪裏開始呢?(哪裏是中文字)? 唉! 我腦筋又不清楚了...

中文應用組件有 AnsiCopy() 視中文字為一個單位, ê以下的程式呢?

var
sTest: string;
begin
sTest := '中文字';
ShowMessage(AnsiCopy(sTest, 2, 2));
sTest := #156 + '中文字';
ShowMessage(AnsiCopy(sTest, 2, 2)); // ??中憒..
end;
講了這麼多, 我的意見是: 回到原點, 除非有人故意搗蛋或者傳入的字串已經有問題, 或者ê個內碼根本沒有字, 否則只用IsDBCSLeadByte()就可以了吧.

 
 
不知道楼上的有没搞懂这样几个东东的区别:
ASCII、DBCS、UNICODE
在DBCS里面,前面的256个字符与扩展ASCII字符集相同,是单字节字符,其它的字符则为
双字节字符,一个字符串里的一个字节可能是一个字符,也可能是半个字符,因此要用到
IsDBCSLeadByte来判断。
UNICODE字符集采用统一的规则,都是双字节的,判断是否UNICODE要经过更复杂的测试,
用IsUnicodeText。
至于判断是否中文,还要根据编码所处的范围来判断。
 
各位大虾!我是越搞越糊涂了!?>???

^_^
 
呵呵,我也看晕了
 
汉字字库是双字节ASCII码,在编码规范中明确规定了各种编码的数值范围,如汉字打头的一个字是1,简体为1X,你去查一下相关规范,可以知道big5的编码数值范围,然后在程序中做一判断,就可以解决问题了.
 
后退
顶部