全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:171
推到 Plurk!
推到 Facebook!

unicode 截取字串

答題得分者是:tick228
wangccw
一般會員


發表:19
回覆:35
積分:15
註冊:2005-01-30

發送簡訊給我
#1 引用回覆 回覆 發表時間:2018-01-30 18:02:58 IP:125.227.xxx.xxx 未訂閱
在以前非 unicode 版本,我要取一個字串的前面幾個字,我會使用以下方式。 


[code delphi]
// @param strlength 字串長度(一個字算2byte)
// @param i 0:取前半段 ,1:取後半段
function TForm1.cutMyString(str: string; strlength, i: integer): string;
var
frontStr: string;
afterStr: string;
index: integer;
begin
frontStr := '';
afterStr := '';
if (length(str) > 0) then begin
index := 1;

while (index <= length(str)) do begin
if (isBig5(copy(str, index, 1)) = true) then begin
if (index < strlength) then begin
frontStr := frontStr + copy(str, index, 2);
end else begin
if (index < length(str)) then begin
afterStr := afterStr + copy(str, index, 2);
end;
end;

index := index + 2;
end else begin
if (index <= strlength) then
frontStr := frontStr + copy(str, index, 1)
else
afterStr := afterStr + copy(str, index, 1);

index := index + 1;
end;
end;
end;

if (i = 0) then result := frontstr;
if (i = 1) then result := afterStr;
end;

function TForm1.isBig5(str: string): boolean;
var
i: integer;
begin
result := false;
for i := 1 to length(str) do
begin
if (IsDBCSLeadByte(Byte(str[i])) = true) then
begin
result := true;
break;
end;
end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
a : String;
b : string;
begin

a := '住臺北市中山區八德路二段203號7樓';
b:=cutMyString(a,28,0);
showmessage(b);
//b 的內容 =住臺北市中山區八德路二段203
//第 28個 byte 是 "號" 的前半段,所以會不取
end;

[/code]

請問到了 delphi xe 版本之後(unicode),該如何實現 cutString 同樣的結果。
是否能給個方向。



我試過使用先將 欲截取的字串轉成 ansiString 再使用 copy 方式取得,但指定取得的長度最後一個byte 若指到一半的中文字,則會變 ?
使用 System.SysUtils.ByteType 來判斷是否為中文字,總是回傳單字節,在此先謝謝各位了

備註:
1. 在 中文字一樣算 2byte。
2. 長度最後一個byte 若不是完整的中文字,就不取。

謝謝




編輯記錄
wangccw 重新編輯於 2018-01-31 03:25:57, 註解 無‧
tick228
中階會員


發表:1
回覆:32
積分:66
註冊:2003-11-03

發送簡訊給我
#2 引用回覆 回覆 發表時間:2018-01-30 23:05:49 IP:101.15.xxx.xxx 未訂閱
unicode 裏, 不管中英數符, 每個 char 皆是兩個 byte,
所以 unicode 要取字段最簡單, 只需 Copy 就可.
例:
Str := 'ABC1234中文中數字';
S := Copy(Str, 1, 4); => 'ABC1'
S := Copy(Str, 6, 4); => '34中文'
S := Copy(Str, 9, 4); => '文中數字'
===================引 用 wangccw 文 章===================
在以前非 unicode 版本,我要取一個字串的前面幾個字,我會使用以下方式。

請問到了 delphi xe 版本之後(unicode),該如何實現 cutString 同樣的結果。
是否能給個方向。

我試過使用先將 欲截取的字串轉成 ansiString 再使用 copy 方式取得,但指定取得的長度最後一個byte 若指到一半的中文字,則會變 ?
使用 System.SysUtils.ByteType 來判斷是否為中文字,總是回傳單字節,在此先謝謝各位了

備註:
1. 在 中文字一樣算 2byte。
2. 長度最後一個byte 若不是完整的中文字,就不取。

謝謝




wangccw
一般會員


發表:19
回覆:35
積分:15
註冊:2005-01-30

發送簡訊給我
#3 引用回覆 回覆 發表時間:2018-01-31 02:09:24 IP:112.104.xxx.xxx 未訂閱
謝謝 tick228 的回覆,你誤會我的意思了,我這樣問,是為了要做資料的排版。


或者說,在 unicode 下,該如何判斷每個字為"全型" 或 "半型",這樣我才能知道如何編排字串。

例如:
Str := '中文字ABc數字1234夾雜其中';

我要切成以下的結果,假設要切成每行 長度 6 ( 視覺上的每段"長度" 一致 )

結果如下
'中文字' // ansiString 長度為 6
'ABc數' // ansiString 長度為 5 , 第6個 char為中文字 (字), 超出長度塞不進去,所以"字" 改填到第三行
'字1234' // ansiString 長度為 6
'夾雜其' //ansiString 長度為 6
'中' //ansiString 長度為 2

可以看到,我每行要 copy 的長度都不一樣,但 ansiString 長度會以 6 為主。

先謝謝了


===================引 用 tick228 文 章=================== unicode 裏, 不管中英數符, 每個 char 皆是兩個 byte,
所以 unicode 要取字段最簡單, 只需 Copy 就可.
例:
Str := 'ABC1234中文中數字';
S := Copy(Str, 1, 4); => 'ABC1'
S := Copy(Str, 6, 4); => '34中文'
S := Copy(Str, 9, 4); => '文中數字'




編輯記錄
wangccw 重新編輯於 2018-01-31 05:05:53, 註解 無‧
jcjroc
高階會員


發表:21
回覆:279
積分:115
註冊:2002-09-18

發送簡訊給我
#4 引用回覆 回覆 發表時間:2018-01-31 11:30:04 IP:210.61.xxx.xxx 未訂閱
大於0xff絕對不會是英數字(ansi範圍)
===================引 用 wangccw 文 章===================
謝謝 tick228 的回覆,你誤會我的意思了,我這樣問,是為了要做資料的排版。


或者說,在 unicode 下,該如何判斷每個字為"全型" 或 "半型",這樣我才能知道如何編排字串。

例如:
Str := '中文字ABc數字1234夾雜其中';

我要切成以下的結果,假設要切成每行 長度 6 ( 視覺上的每段"長度" 一致 )

結果如下
'中文字' // ansiString 長度為 6
'ABc數' // ansiString 長度為 5 , 第6個 char為中文字 (字), 超出長度塞不進去,所以"字" 改填到第三行
'字1234' // ansiString 長度為 6
'夾雜其' //ansiString 長度為 6
'中' //ansiString 長度為 2

可以看到,我每行要 copy 的長度都不一樣,但 ansiString 長度會以 6 為主。

先謝謝了


===================引 用 tick228 文 章=================== unicode 裏, 不管中英數符, 每個 char 皆是兩個 byte,
所以 unicode 要取字段最簡單, 只需 Copy 就可.
例:
Str := 'ABC1234中文中數字';
S := Copy(Str, 1, 4); => 'ABC1'
S := Copy(Str, 6, 4); => '34中文'
S := Copy(Str, 9, 4); => '文中數字'




tick228
中階會員


發表:1
回覆:32
積分:66
註冊:2003-11-03

發送簡訊給我
#5 引用回覆 回覆 發表時間:2018-01-31 11:56:59 IP:101.13.xxx.xxx 未訂閱
原來是要列印排版, 真是誤會了~~

IsDBCSLeadByte() 只適用於 AnsiString 判斷,
要判斷 Unicode 是否為半型英數字, 可判斷 char 是否小於 #$0100,

if Str[i] < #$0100 then
// 半型
else
// 全型
;
不過, 這種做法, 只能用於等寬字型(如 細明體, Courier New ..),
可考慮使用 Canvas.TextWidth() 一一判斷最適長度, 例:
j := Length(Str);
for i:= 1 to Length(Str) do
if Canvas.TextWidth(Copy(Str,1,i)) > PrintWidth then
begin
j := i-1;
Break;
end;
S := Copy(Str, 1, j); // 截取字串
這樣的方式, 就可不限字型.

===================引 用 wangccw 文 章===================
謝謝 tick228 的回覆,你誤會我的意思了,我這樣問,是為了要做資料的排版。


或者說,在 unicode 下,該如何判斷每個字為"全型" 或 "半型",這樣我才能知道如何編排字串。

例如:
Str := '中文字ABc數字1234夾雜其中';

我要切成以下的結果,假設要切成每行 長度 6 ( 視覺上的每段"長度" 一致 )

結果如下
'中文字' // ansiString 長度為 6
'ABc數' // ansiString 長度為 5 , 第6個 char為中文字 (字), 超出長度塞不進去,所以"字" 改填到第三行
'字1234' // ansiString 長度為 6
'夾雜其' //ansiString 長度為 6
'中' //ansiString 長度為 2

可以看到,我每行要 copy 的長度都不一樣,但 ansiString 長度會以 6 為主。

先謝謝了
wangccw
一般會員


發表:19
回覆:35
積分:15
註冊:2005-01-30

發送簡訊給我
#6 引用回覆 回覆 發表時間:2018-01-31 14:14:23 IP:114.137.xxx.xxx 未訂閱
謝謝  tick228 和   jcjroc 大大的幫忙,以下是我以各位前輩說的方式作出來的簡單判斷方式
這樣即可解決我的困擾。(最主要只要知道每一個char不是英文,接下來就好好辦了)


[code delphi]
//判斷漢字
function TForm1.isHz(chr: wideChar): boolean;
begin
if ( ord(chr) > 127 ) then begin
result := true;
end else begin
result := false;
end;
end;


procedure TForm1.Button1Click(Sender: TObject);
var
str: String;
i : integer;
begin
Str := '1,Q你好2@';

for i := 0 to Str.Length-1 do begin
showmessage(booltostr( isHz(Str.Chars[i]) ));
end;

end;

[/code]

再次謝謝各位先輩,解決我的問題



編輯記錄
wangccw 重新編輯於 2018-01-31 14:49:22, 註解 無‧
wangccw 重新編輯於 2018-01-31 14:51:03, 註解 無‧
wangccw 重新編輯於 2018-01-31 14:51:42, 註解 無‧
wangccw 重新編輯於 2018-01-31 14:52:06, 註解 無‧
wangccw 重新編輯於 2018-01-31 18:48:13, 註解 無‧
系統時間:2018-02-24 0:31:23
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!