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

發現了在XE4存在的問題

 
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#1 引用回覆 回覆 發表時間:2013-07-06 23:15:33 IP:114.33.xxx.xxx 未訂閱
To ALL:

最近兩個月在轉移元件的時候,發現原本使用的String 資料類別轉為 AnsiString 類別時發生
了下列狀況(in Delphi XE4)

Ex:
var tempStr,str1:AnsiString;
str2:AnsiString;
li:integer;
begin
tempStr := '測試中文';
str1 := AnsiToUtf8(tempStr); //-->自此,轉出來的字串是UTF-8格式的資料,一樣是 '測試中文'

但是
li := Length(str1); //--> 此時,str1的資料正常的UTF-8字串轉眼變成一堆亂碼!!

當寫法換成

str2 := str1;

li := Length(str2) ; //--> 此時,str2的UTF-8字串資料就不會被破壞變成亂碼

end;

這是個從XE系列之後就一直出現的現象,直到小弟發現了之後,多做了一道程序之後,問題才解決

不知道大家是否經歷過這樣的現象?? 小弟找這個問題找了足足兩個多月.....

原本以為是編碼的問題,但是看起來又不像是.......

編輯記錄
JL9168 重新編輯於 2013-07-06 23:17:13, 註解 無‧
P.D.
版主


發表:571
回覆:3880
積分:3666
註冊:2006-10-31

發送簡訊給我
#2 引用回覆 回覆 發表時間:2013-07-07 11:21:16 IP:220.136.xxx.xxx 未訂閱
幫你轉發到EMBARCADERO 專區, 看看會不會有回應!
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#3 引用回覆 回覆 發表時間:2013-07-07 12:25:50 IP:114.33.xxx.xxx 未訂閱
謝謝 PD大大
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#4 引用回覆 回覆 發表時間:2013-07-07 20:04:29 IP:175.96.xxx.xxx 訂閱
 沒來上我unicode祕技講座,否則就知道是為什麼。不過,你可以翻我不久前
回覆的文章有解(html方面)。但我沒深入回覆原理!目前我人在外面,打字很不方便。若回
去,有必要的話,再多回一點!
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#5 引用回覆 回覆 發表時間:2013-07-07 22:30:06 IP:114.42.xxx.xxx 訂閱
剛回到家,… 一看… (驚!) 上回我回的人就是樓主啊~~

所以你應該知道要改成UTF8String,而不能使用AnsiString啊~

http://delphi.ktop.com.tw/board.php?cid=30&fid=69&tid=104930


===================引 用 aftcast 文 章===================
沒來上我unicode祕技講座,否則就知道是為什麼。不過,你可以翻我不久前
回覆的文章有解(html方面)。但我沒深入回覆原理!目前我人在外面,打字很不方便。若回
去,有必要的話,再多回一點!
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#6 引用回覆 回覆 發表時間:2013-07-07 22:53:06 IP:114.33.xxx.xxx 未訂閱
不過問題點真的不是使用UTF8String這個問題,而是在這個編譯環境中,只要寫程式的人,將資料倒入不應該
擅自變更原有資料的函數中,編譯器就應該保證參數資料應該是要絲毫無損的,

所以才會舉出 Length(str1) 這樣的例子,因為程式語言的資料內存是一個語言的根本,程式人員打心理相信
這樣的一個編譯環境,所以才能確切掌握每一行程式的環結是正常的,是可被信賴和控制的

以本例來說,牽連的程式碼有十萬行以上,將近五年累積的可靠程式區段,居然是被程式語言的內存自行修改資料
這樣的衝擊,個人會認為這個開發環境尚不成熟,或是沒有做好身為一個編譯器應該有的最基本要求。

這個感覺在BCB XE4 更是明顯,由編譯環境產生的*.hpp居然還有錯誤,include 變成 include "A1" 、
Package的編譯用到Designintf 與 DesignEditors 都還要自行加這個改那個的,感覺像是在替IDE 除錯,而不是在替程式除錯。


===================引 用 aftcast 文 章===================
剛回到家,… 一看… (驚!) 上回我回的人就是樓主啊~~

所以你應該知道要改成UTF8String,而不能使用AnsiString啊~

http://delphi.ktop.com.tw/board.php?cid=30&fid=69&tid=104930


===================引 用 aftcast 文 章===================
沒來上我unicode祕技講座,否則就知道是為什麼。不過,你可以翻我不久前
回覆的文章有解(html方面)。但我沒深入回覆原理!目前我人在外面,打字很不方便。若回
去,有必要的話,再多回一點!
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#7 引用回覆 回覆 發表時間:2013-07-07 23:05:03 IP:114.33.xxx.xxx 未訂閱
如果不是因為要測試離線網頁資料,還真的找不到這樣的問題;原因就是因為直接輸出的檔案不需要用到

像是Length( )、Format( )這一類的字串處理函數,也許真的是因為要支援Unicode而有所修正,但是

既然程式人員的用意並不是要更動到資料,所以選用這些函式;然而卻因此變動到資料,比較正確的

方式不應該是這樣........即使用了ansistring ,只要在不應該會變動變數內資料的函數中,資料就不應當被變動。
倘若真的必須要全改為使用Utf8String.......天啊,那很難統計把舊程式或舊系統Mount上來要花多少時間成本.........

會不會最後變成......重寫比較快??!! 因為不知道下一顆地雷在那兒......

除了這些之外,其餘的資料轉換就覺得比較理所當然,像是

var str1:AnsiString;
ws:WideString;
PWS:PWideChar;
begin

pws := PWideChar(str1); ---->這是錯誤的轉換......OK!! 這個道理可以接受

應該要改成
ws := str1;
PWS := PWideChar(WS);

這些不同的編碼字串間的轉換,相形之下是合情合理的.....就不能算是Bug!!





編輯記錄
JL9168 重新編輯於 2013-07-07 23:12:46, 註解 無‧
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#8 引用回覆 回覆 發表時間:2013-07-07 23:21:47 IP:114.33.xxx.xxx 未訂閱
還是要感謝aftcast 大大之前熱心回答小弟的問題,感激之至

只是對這樣的問題覺得有說出來讓大家參考的必要,若真的碰上了;能夠技巧性的繞過這樣的問題。
無非也是希望這個開發環境可以更可靠,畢竟還是希望用它的使用者能夠再多增加一些........

至於Update1是否有針對這樣的問題........還不清楚.....可能要去找相關的資料了......
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#9 引用回覆 回覆 發表時間:2013-07-08 07:00:17 IP:114.42.xxx.xxx 訂閱
嗯,我了解你說的情形與苦處! 但事實上是因為你還不夠了解新版的string方面的處理與架構。我可以肯定不是編譯器上的問題或錯誤,是因你"誤解"或說"誤用"了新的字串功能。當然,我也覺得embt在文件與書本上 (唉,又是老到不行的話…但無解) 並沒有很強的說明新字串的架構與用法,所以多數人還是不理解。

我的講座課堂上就有解說細節--如:新字串的結構。 我簡言之,新字串是一種「編碼感知」的字串。字串本身有一個「標示區」會記載它是什麼編碼,好比說是cp950(即big5) 或是 utf8 (cp65001)。 而為何又稱「感知」? 因為在你把 字串設定給字串時,它會「全自動的」去偵測編碼那個「標示區」,進一步的幫你做編碼轉換! 看似很貼心,但不明白的人會被搞死…因為不知何時被動了手腳… 不過,當你很明白這架構後,你就會覺得有貼心到。

以你所舉的例子來說,我肯你應該是有簡略了一些程式碼… 單純的執行到Length(str1)這一行後,str1的內容絕對還沒有任何變化。我把你的程式貼到xe3,經反組譯,加上翻cpu畫面裡的memory的二進位。肯定還是utf8的碼 (以你的這個例子)。 我想你說會出現亂碼應該是在那一行後面還有一些關於字串的show出,或是字串的再設給誰之類的…

再補充一些: 新版的AnsiString是不等於UTF8String的 (原因就是我剛講的「感知編碼」的關係,因為二者的標示區的值是不同的,所以算是不一樣的字串)。
str1,str4:AnsiString;
str2,str3:UTF8String;
str1 := '中文';
str2 :='中文";

str1在記憶體中是A4A4A4E5
str2則是 E4B8ADE69687

又,事實上你根本不需要用AnsiToUtf8() 這個函式。你只要:

str3 := str1; //這行就搞定,why? 因為全自動感知而幫你轉碼

相反的

str4 := str3; //這時候的str4裡放的是A4A4A4E5, 又自動的被轉換了


所以,從此,big5轉utf8或utf8轉big5 (但這要小心,因為utf8是unicode,比如堃這個字,轉後會變?) 通通都是 一行搞定,只要 「你的字串宣告是正確的!」

而你的這一行:
str1 := AnsiToUtf8(tempStr); //-->自此,轉出來的字串是UTF-8格式的資料,一樣是 '測試中文'

事實上是「錯誤的」寫法(在新版上),因為還是那句話,明明是utf8的字串,你硬塞給big5的字串。然而…為何str1真的還是放著utf8的編碼? 因為…那個函式傳回的是rawbytestring…

說到這裡,愈來會愈深入原理部份,但一時半刻難說清。但有幾個重要的概念可以給個hint : 「到底ansistring的定義是什麼? 為什麼這樣問? 因為以前utf8,明明就是用ansitring來放的啊…,而以剛你的例子來說,也真的放了utf8的內容… 而rawbytestring又是啥用的? 」

若不考慮深入的了解原理,那我覺得就是用 UTF8String 去接你的AnsiToUtf8函式就對了( 新版正解做法),「其實再強調一次,事實上這個函式在新版是不需要使用了,因為一行搞定」。

希望以上能有一點幫助。至於若你百分百肯定你的例子(就那些行數,沒有別的,也沒有省)到了lengh()那行就變… 我真的也很認真的想知道是否我真的錯過了什麼? 還請反饋讓我知道,感謝!

===================引 用 JL9168 文 章===================
To ALL:

最近兩個月在轉移元件的時候,發現原本使用的String 資料類別轉為 AnsiString 類別時發生
了下列狀況(in Delphi XE4)

Ex:
var tempStr,str1:AnsiString;
str2:AnsiString;
li:integer;
begin
tempStr := '測試中文';
str1 := AnsiToUtf8(tempStr); //-->自此,轉出來的字串是UTF-8格式的資料,一樣是 '測試中文'

但是
li := Length(str1); //--> 此時,str1的資料正常的UTF-8字串轉眼變成一堆亂碼!!

當寫法換成

str2 := str1;

li := Length(str2) ; //--> 此時,str2的UTF-8字串資料就不會被破壞變成亂碼

end;

這是個從XE系列之後就一直出現的現象,直到小弟發現了之後,多做了一道程序之後,問題才解決

不知道大家是否經歷過這樣的現象?? 小弟找這個問題找了足足兩個多月.....

原本以為是編碼的問題,但是看起來又不像是.......

------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2013-07-08 07:03:26, 註解 無‧
aftcast 重新編輯於 2013-07-08 07:29:28, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#10 引用回覆 回覆 發表時間:2013-07-08 07:22:02 IP:114.42.xxx.xxx 訂閱
喔,剛想到一件重要的事沒補充:

若某函式的宣告長這樣 (容我用c 語法較熟)

foo( String str)
{
String inStr = str;
Lenght(inStr);

}

AnsiString ans = "中文";
foo(ans);
這時候 foo裡面的 inStr 已經是unicode,而不是原來的big5了…
原因? 一樣: 編碼感知 問題,全自動幫你(雞婆)轉了,若你是用 var 傳入(delphi裡的傳址) 你就更慘了。

又以你經常處理utf8的功能,想必經常遇到的應該是
bar (AnsiString ans)
但你把一個也叫
AsnsiString str1 (但事實上放的是utf8的內容,經ansiToUtf8函式而得),你會以為 ansistrin 的字串放入 ansistring的參數…一切不會變吧…
但,可能變了 (我說「可能」是因為我沒這樣用,我此刻也沒測)。若變是為什麼? 因為它str1這個參數一直真的被當「big5」來處理所有的工具函式等等的…但你卻傳給它的是一個
「偽」ansistring(記得ansistring是big5,新版的)。

以上補充
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#11 引用回覆 回覆 發表時間:2013-07-08 10:42:00 IP:114.33.xxx.xxx 未訂閱
感謝aftcaft這麼深度的說明

>> 因為以前utf8,明明就是用ansitring來放的啊…,而以剛你的例子來說,也真的放了utf8的內容…

其實這才是重點所在,也因為考量相容性,一時之間沒有辦法把全部的程式都依照"新式" 的做法來處理,
所以"把有處理到UTF-8字串變數全都改為UTF8String" 這件事就變成一個遙不可及的想法,因為包袱太大了。

>> 你會以為 ansistrin 的字串放入 ansistring的參數…一切不會變吧…

實際上真的變了,以一個開發者的角度來說,也許認為這是個貼心的方式;但以一個使用者的角度來說
,這樣的狀態是令人擔憂的(Delphi 給人的印象就是"Strong type"類型的程式語言)。

不過現在知道了,新的系統不會再用這類方式來寫了。

>>AnsiString ans = "中文";
>>foo(ans);
>>這時候 foo裡面的 inStr 已經是unicode,而不是原來的big5了…
>>原因? 一樣: 編碼感知 問題,全自動幫你(雞婆)轉了,若你是用 var 傳入(delphi裡的傳址) 你就更慘了。

感覺就是整個環境都改了,連舊的程式碼,內定的系統函式也不相容了........T_T........ 只有接受了........

如果原來可用的函式已經不適用了,那還有哪些函式是不能這樣做或是需要重新檢視的呢??
後來這件事情的處理方式就是,XE以後的版本自成一個系列;同一套套件以後要維護兩個版本。

但會不會隨之而來的問題就是....也許在新舊版本開發出來的套件中,編譯出來的DLL會有相容性的問題。
一旦有,那就表示之前的舊版模組環境都需要全面翻寫或是改寫,茲事體大..........

還有幾個問題想請教

1.AnsiString類型應該不能定義為"專為處理big5字串"的變數吧?? 而是放置由ASCII Code組成的字串資料....對吧!!

2.如果在Delphi 中 Function() Result := '' ; 這一類的函式,是否也就不能以ansistring來定義了....對吧??

那如果我們不確定傳回的字串資料是big5 ,gb2312 or 其他內碼.....那狀況就變得很棘手了....


再次感謝您的回答


===================引 用 aftcast 文 章===================
喔,剛想到一件重要的事沒補充:

若某函式的宣告長這樣 (容我用c 語法較熟)

foo( String str)
{
String inStr = str;
Lenght(inStr);

}

AnsiString ans = "中文";
foo(ans);
這時候 foo裡面的 inStr 已經是unicode,而不是原來的big5了…
原因? 一樣: 編碼感知 問題,全自動幫你(雞婆)轉了,若你是用 var 傳入(delphi裡的傳址) 你就更慘了。

又以你經常處理utf8的功能,想必經常遇到的應該是
bar (AnsiString ans)
但你把一個也叫
AsnsiString str1 (但事實上放的是utf8的內容,經ansiToUtf8函式而得),你會以為 ansistrin 的字串放入 ansistring的參數…一切不會變吧…
但,可能變了 (我說「可能」是因為我沒這樣用,我此刻也沒測)。若變是為什麼? 因為它str1這個參數一直真的被當「big5」來處理所有的工具函式等等的…但你卻傳給它的是一個
「偽」ansistring(記得ansistring是big5,新版的)。

以上補充
編輯記錄
JL9168 重新編輯於 2013-07-08 11:09:11, 註解 無‧
ANDY8C
資深會員


發表:114
回覆:582
積分:299
註冊:2006-10-29

發送簡訊給我
#12 引用回覆 回覆 發表時間:2013-07-08 14:00:18 IP:60.245.xxx.xxx 未訂閱
您的問題我也遇過了
原本用 DELPHI 2007 開發的軟體,一切順利,加上 TNT 的UNICODE 元件,也都順利
有一天,想替客戶增加真正的 UNICODE 版本,所以買了 XE2 ,從此日子就累了
我用的 3RD 元件不多,只有三個,大都是自己寫的,
我將 D2007 的程式,直接在 XE2 重新編譯....UI 的輸入及輸出都OK,
的確解決了 UNICODE 的問題,完全無痛.......

但是.....
通訊的功能,傳輸字串的功能,我就遇到很大的問題(標籤機的自行描繪字型/控制命令...等),
都是一些莫名其妙的問題,所以 D2007 改到 XE2 ,絕非 ANSI STRING 轉 WIDE STRING 的單純問題.
我都不太敢講,因為我對 XE2 不是很熟......

出道早,所以累計太多小程式要改/檢查.

目前我的程式,也是一支一支的改(D2007 -> XE2) ;也為將來升級到 XE4 的問題準備,
說實在的,我是接案謀生,不是為研究 DELPHI 而用 DELPHI,
我不會用太高深的技巧來寫程式,

所以......不是也想了解是誰的問題,只要在客戶端運作正常就好.

以上,謝謝您

===================引 用 JL9168 文 章===================
還是要感謝aftcast 大大之前熱心回答小弟的問題,感激之至

只是對這樣的問題覺得有說出來讓大家參考的必要,若真的碰上了;能夠技巧性的繞過這樣的問題。
無非也是希望這個開發環境可以更可靠,畢竟還是希望用它的使用者能夠再多增加一些........

至於Update1是否有針對這樣的問題........還不清楚.....可能要去找相關的資料了......
------
---------------------------------------
偶爾才來 KTOP ,交流條碼問題,在 FB [條碼標籤達人] 社團留言,感恩.
編輯記錄
ANDY8C 重新編輯於 2013-07-08 14:03:19, 註解 無‧
ANDY8C
資深會員


發表:114
回覆:582
積分:299
註冊:2006-10-29

發送簡訊給我
#13 引用回覆 回覆 發表時間:2013-07-08 15:39:27 IP:60.245.xxx.xxx 未訂閱
請問一下,您的問題是....字串內容還是字串長度有問題 ?
我剛用 XE2 測試
STR1,STR2 正常.....但 LENGTH 是 12,不知是否是您的問題 ??

我寫的測試程式
http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=105306



===================引 用 JL9168 文 章===================
To ALL:

最近兩個月在轉移元件的時候,發現原本使用的String 資料類別轉為 AnsiString 類別時發生
了下列狀況(in Delphi XE4)

Ex:
var tempStr,str1:AnsiString;
str2:AnsiString;
li:integer;
begin
tempStr := '測試中文';
str1 := AnsiToUtf8(tempStr); //-->自此,轉出來的字串是UTF-8格式的資料,一樣是 '測試中文'

但是
li := Length(str1); //--> 此時,str1的資料正常的UTF-8字串轉眼變成一堆亂碼!!

當寫法換成

str2 := str1;

li := Length(str2) ; //--> 此時,str2的UTF-8字串資料就不會被破壞變成亂碼

end;

這是個從XE系列之後就一直出現的現象,直到小弟發現了之後,多做了一道程序之後,問題才解決

不知道大家是否經歷過這樣的現象?? 小弟找這個問題找了足足兩個多月.....

原本以為是編碼的問題,但是看起來又不像是.......

------
---------------------------------------
偶爾才來 KTOP ,交流條碼問題,在 FB [條碼標籤達人] 社團留言,感恩.
編輯記錄
ANDY8C 重新編輯於 2013-07-08 15:43:02, 註解 無‧
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#14 引用回覆 回覆 發表時間:2013-07-08 16:59:41 IP:27.51.xxx.xxx 未訂閱
是字串的內容被修改了,內容是原本轉好的UTF-8字串

-->>> 因為以前utf8,明明就是用ansitring來放的啊…,而以剛你的例子來說,也真的放了utf8的內容…


//---------------------------------------------------------------------------
<部分原始碼>

Part1.----->Format( ) 出來的結果ResStr字串就由UTF-8 字串變為亂碼

ResSt r := Format('HTTP/1.0 200 OK'#13#10
'Content-Type: text/html'#13#10
'Content-Length: %d'#13#10
'Content:'#13#10#13#10'%s', [Length(ResStr), ResStr]);

後來這一段把Format( ) 拿掉,就正確了。

Part2 --> Length( ) 出來的結果ResStr字串又從UTF-8 字串變為亂碼

//回應給WebClient端的資訊!!
CardiTemp := Length(ResStr);
//---------------------------------------------------------------------------------------------------------
大致上是這樣

所以如果要測試
Var str:AnsiString;
len:integer;
begin
str := '測試字串'; <----這裡要放入UTF-8編碼的中文字,不是Big5編碼的字串

len := Length(str);

end;
===================引 用 ANDY8C 文 章===================
請問一下,您的問題是....字串內容還是字串長度有問題 ?
我剛用 XE2 測試
STR1,STR2 正常.....但 LENGTH 是 12,不知是否是您的問題 ??

我寫的測試程式
http://delphi.ktop.com.tw/board.php?cid=31&fid=79&tid=105306



===================引 用 JL9168 文 章===================
To ALL:

最近兩個月在轉移元件的時候,發現原本使用的String 資料類別轉為 AnsiString 類別時發生
了下列狀況(in Delphi XE4)

Ex:
var tempStr,str1:AnsiString;
str2:AnsiString;
li:integer;
begin
tempStr := '測試中文';
str1 := AnsiToUtf8(tempStr); //-->自此,轉出來的字串是UTF-8格式的資料,一樣是 '測試中文'

但是
li := Length(str1); //--> 此時,str1的資料正常的UTF-8字串轉眼變成一堆亂碼!!

當寫法換成

str2 := str1;

li := Length(str2) ; //--> 此時,str2的UTF-8字串資料就不會被破壞變成亂碼

end;

這是個從XE系列之後就一直出現的現象,直到小弟發現了之後,多做了一道程序之後,問題才解決

不知道大家是否經歷過這樣的現象?? 小弟找這個問題找了足足兩個多月.....

原本以為是編碼的問題,但是看起來又不像是.......

編輯記錄
JL9168 重新編輯於 2013-07-08 17:00:45, 註解 無‧
JL9168 重新編輯於 2013-07-08 17:12:15, 註解 無‧
JL9168 重新編輯於 2013-07-08 17:13:23, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#15 引用回覆 回覆 發表時間:2013-07-08 17:32:48 IP:114.42.xxx.xxx 訂閱

>>如果原來可用的函式已經不適用了,那還有哪些函式是不能這樣做或是需要重新檢視的呢??
>>後來這件事情的處理方式就是,XE以後的版本自成一個系列;同一套套件以後要維護兩個版本。

如果以utf8的問題來說,建議還是將舊碼改成utf8string,因為舊碼會自動把這個型別轉成ansistring (我想這是當年留下的伏筆)。而同一份碼若到新版編譯,則當然就不會如剛講的被轉成ansistring,而是真的utf8string這個型別! 於是可以相容。 然而,事實上問題可能不會簡單到只要換型別,因為你可能寫了一堆的自己函式,而其中的參數是宣告成ansistring,但傳入的是「經ansistoutf8所得的anistring(在新版已不能再稱anistring)」,於是你要把參數也換成utf8string。舉例,你有個函式
foo(ansistring str) //你心中了解將要傳入的是utf8的字串,而不是big5的字串。那麼你就要改成
foo(utf8string str) //改成這樣後,新舊也都合。


>>但會不會隨之而來的問題就是....也許在新舊版本開發出來的套件中,編譯出來的DLL會有相容性的問題。

不會! 不同編譯器編出來的dll是封閉的。但你心中依舊要一直記得,若是舊的dll,裡面有ansistring參數,但事實上是要被傳入utf8的資料,那麼你在新版程式中,要呼叫舊的dll時,你自己要先把新的那個字串搞成utf8string後,再呼叫你舊dll裡的那個函式。


還有幾個問題想請教

>>1.AnsiString類型應該不能定義為"專為處理big5字串"的變數吧?? 而是放置由ASCII Code組成的字串資料....對吧!!
對,但更精準的講是…ansistring是專門處理1個字元(1byte)為基礎的字串。也因此,這個特質在以前也可以處理utf8的內容。然而,新版的字串加入了「編碼感知」的功能與標示後,它就不再單純的僅僅處裡一個字元為基礎,而是會動態的去幫你轉碼。舊版的字串沒有那個標示區,也就是說僅存資料(不管你是big5或是utf8或是gb2312…反正都是以單字元為單位 (或許你會想…中文不是二個bytes嗎?…事實上,編譯器是當它一個一個的…。big5在英文字時是不是單一? 是。變中文時是不是變2,是。那和utf8在英文是1,在中文多數是3,是一樣的)。

>>2.如果在Delphi 中 Function() Result := '' ; 這一類的函式,是否也就不能以ansistring來定義了....對吧??

>> 那如果我們不確定傳回的字串資料是big5 ,gb2312 or 其他內碼.....那狀況就變得很棘手了....

嗯,你說的對。所以會有一個叫rawbytestring 的東西,就是為了解你說的這個情形。配合有個查目前string編碼的函式,可以解到底是回傳了什麼。
我給個例子:
procedure TForm9.FormActivate(Sender: TObject);
var str:AnsiString;
rb:RawByteString;
i: integer;
begin
str := '中文';
rb := str;
i := StringCodePage(rb);
end;



------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#16 引用回覆 回覆 發表時間:2013-07-08 18:48:20 IP:114.33.xxx.xxx 未訂閱
不好意思,再多請教一些問題

在尚未發現這個問題時,原本我們以為這樣的情形是因為WinSocket API 或是相關的 API 在XE以後的定義
都因為資料型態的改變而改變了

例如:
原本為PChar( )的參數,都被改成PWideChar( ) 所以才會有這個問題;後來測試過之後才發現
根本不是這樣!!

但是也因此發現了這樣的資料轉換邏輯

var str1:AnsiString;
ws :WideString;
Pws:PWideChar;

Pws := PWideChar(str1); --->這樣似乎資料也會出錯

必須寫成這樣
ws := str1;
Pws := PWideChar(ws);

可以請你說說為何第一個程式為何也不正確呢?? (可是這是可以通過編譯的!!)

另外,有沒有可能有一種情形是

var str1:Ansistring;
str1 := 'Big5字串' 'GB2312字串'; <<----這樣的情形會變成如何?


謝謝你撥冗回答問題
編輯記錄
JL9168 重新編輯於 2013-07-08 18:54:53, 註解 無‧
JL9168 重新編輯於 2013-07-08 18:57:46, 註解 無‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#17 引用回覆 回覆 發表時間:2013-07-08 20:25:07 IP:114.42.xxx.xxx 訂閱
事實上,經過剛一直玩,發現其實在正常的情形下要讓問題變錯很不容易。舉例說,若用ansitoutf8這個函式,轉出來的結果會把原字串的標示區一並修改成utf8的編碼(即使型別上還是你用了ansistring,而非utf8string,但此刻的那個字串已經側底的是「標示是utf8 」, 「內容也是utf8」了,所 以再經轉來轉去,感覺也不太會出錯。

我認為,會出問題,最主要都是因為「在不改標示(事實上你不能手動改,除非你透過函式的傳回值)的前提下,你去修改了該字串的內容為utf8的內容」,這樣的結果會是「頭(標示區)記的是big5,而你身體(內容),卻是utf8。 進一步若在有被換碼的時候,問題就出來,比如說你叫showmessage時會轉一次變成unicode。

底下是我的測試範例:

procedure TForm9.FormActivate(Sender: TObject);
var str,str2,str3:AnsiString;
rb:RawByteString;
i: integer;
u8, uu8:UTF8String;
u16:string;
begin
rb := #$E4#$B8#$AD#$E6#$96#$87; // 中文的utf8的二進位,硬塞
//u8 := #$E4#$B8#$AD#$E6#$96#$87; 這行很有趣,放到u8裡的值已不是你給的,感知呀~~~
str := #$E4#$B8#$AD#$E6#$96#$87; // 這時候的str是掛羊頭賣狗肉的。頭是big5的記錄,身體卻放著utf8的編碼 (以新版的字串觀點)

u8 := rb; // 這是頭與身體都是合的正確字串
//str := rb;
Length(str); // 事實上length是絕對不可能改變任何的字串內容的,它只是把字串裡的「長度」讀出來,你mark這行是一樣的結果
str2 := 'CDE';
str2 := str2 str; // str2 現在是頭是big5,身體是混種,裡面有big5的cde,也有utf8編碼的「中文」
uu8 := 'ABC';
uu8 := uu8 u8;
ShowMessage(str2); // 這裡轉一次unicode,於是出錯
ShowMessage(uu8); // uu8是正確的,所以再轉unicode也是不會錯!
rb := str;
i := StringCodePage(rb);
str3 := AnsiToUTF8(str);
end;


以上的範例極重要,若可以清楚的知道就一定會內力變強。當然,可能要配合會在cpu的debug畫面上去找出字串的所在記憶體二進位的地方,希望上回上我課的學員還會記得怎麼處理!


===================引 用 JL9168 文 章===================
是字串的內容被修改了,內容是原本轉好的UTF-8字串

-->>> 因為以前utf8,明明就是用ansitring來放的啊…,而以剛你的例子來說,也真的放了utf8的內容…


//---------------------------------------------------------------------------
<部分原始碼>

Part1.----->Format( ) 出來的結果ResStr字串就由UTF-8 字串變為亂碼

ResSt r := Format('HTTP/1.0 200 OK'#13#10
'Content-Type: text/html'#13#10
'Content-Length: %d'#13#10
'Content:'#13#10#13#10'%s', [Length(ResStr), ResStr]);

後來這一段把Format( ) 拿掉,就正確了。

Part2 --> Length( ) 出來的結果ResStr字串又從UTF-8 字串變為亂碼

//回應給WebClient端的資訊!!
CardiTemp := Length(ResStr);
//---------------------------------------------------------------------------------------------------------
大致上是這樣

所以如果要測試
Var str:AnsiString;
len:integer;
begin
str := '測試字串'; <----這裡要放入UTF-8編碼的中文字,不是Big5編碼的字串

len := Length(str);

end;

------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
編輯記錄
aftcast 重新編輯於 2013-07-08 20:53:23, 註解 無‧
aftcast 重新編輯於 2013-07-08 21:07:42, 註解 修正我之前給的範例中的說明部份!‧
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#18 引用回覆 回覆 發表時間:2013-07-08 20:47:54 IP:114.42.xxx.xxx 訂閱

===================引 用 JL9168 文 章===================
不好意思,再多請教一些問題

在尚未發現這個問題時,原本我們以為這樣的情形是因為WinSocket API 或是相關的 API 在XE以後的定義
都因為資料型態的改變而改變了

例如:
原本為PChar( )的參數,都被改成PWideChar( ) 所以才會有這個問題;後來測試過之後才發現
根本不是這樣!!

但是也因此發現了這樣的資料轉換邏輯

var str1:AnsiString;
ws :WideString;
Pws:PWideChar;

>>>>>>>>>> Pws := PWideChar(str1); --->這樣似乎資料也會出錯

上面那行以語法來說是正確的,故一定可以編過,但錯是邏輯,這種錯最難debug。以你這個為例: 因為str1裡面假設放了ABC這三個字元,它在記憶體是0x41 0x42 0x43。而指標若是PAnsiChar的話,「每移動一次,是記憶體往下移一個byte」,若指標為PWideChar,則「每移動一次,是記憶體往下移二個byte」。於是你想看看… 你的 ABC 正常是要被移二。若你用了PAnsiChar移二次,剛好到0x43,嗯,正確!!! 若你是PWideChar,被移了二次,就爆爆爆點了…跑到C這個字元外的不明內容上!

若你先把AnsiString改成WideString,那麼你的記憶體變成 0x41 0x00 0x42 0x00 0x43 0x00 (別問我為何有0在中間…因為它是unicode啊)。因此你變成了6個bytes,那麼你用PWideChar來移動,耶……移動一次,剛好在 0x42,移動第二次,剛好0x43… 真是合的。
但以上的說明都是在英數的情形下,若是中文字,就沒那麼剛好,因為中間不會是 0x00 補在中間啦!


必須寫成這樣
ws := str1;
Pws := PWideChar(ws);

可以請你說說為何第一個程式為何也不正確呢?? (可是這是可以通過編譯的!!)

另外,有沒有可能有一種情形是

var str1:Ansistring;
>>>>>>>>>>>>>>>>>>>str1 := 'Big5字串' 'GB2312字串'; <<----這樣的情形會變成如何?


會變亂碼!(若以unicode轉後來看,比如用showmessage) 因為str1 是ansistring,所以它不會對右邊的「常數」字串動任何的手腳,直就「接上去」
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
aftcast
站務副站長


發表:81
回覆:1482
積分:1762
註冊:2002-11-21

發送簡訊給我
#19 引用回覆 回覆 發表時間:2013-07-08 21:16:24 IP:114.42.xxx.xxx 訂閱
 再補充上面講的 pwidechar 指標等相關問題。

一般來說,變指標有二種可能需求,
一種是要被 c 語言之api (包含windows sdk api),直接叫用裡面的字串內容。
第二種,是會被再拿來搬移,修改,補上一些字用 : 這種情形下就會考量到我剛講的移動問題。

以ansistring要給function當參數用時… 若function要求ansistring的指標,理所當然你一定要給pansichar,一方面是一次動一個byte,二方面該字串的編碼是對方要的(如big5(含英數))。

若對方要的是 pwidechar 的參數,那你要先轉成widestring是應該的,因為編碼它要求是unicode,其次,也可能它會在裡面一次搬二個byte來做一些memory的處理。
------



蕭沖
--All ideas are worthless unless implemented--

C++ Builder Delphi Taiwan G+ 社群
http://bit.ly/cbtaiwan
JL9168
中階會員


發表:133
回覆:223
積分:76
註冊:2011-09-29

發送簡訊給我
#20 引用回覆 回覆 發表時間:2013-07-09 06:52:39 IP:114.33.xxx.xxx 未訂閱
OK ,現在清楚的知道原因了;其實這些自己發展的函數之中,多了一個自轉UTF-8的函式 >>AnisStrToUtf8( )

當初的定義是把它從D7的基礎單元分離出來,用來完成D7以下版本的UTF-8轉移公用函式,所以定義上如下

function AnisStrToUtf8(inStr:AnsiString):AnsiString;

轉到XE系列之後,雖然轉出來的資料是正確的UTF-8字串,但是在XE環境就會被變動了!!

所以用塞UTF-8到AnsiString的做法基本上是符合這個情境的。

為何不用新的做法,道理也很簡單,因為每一次輸出網頁資料不一定都是使用UTF-8編碼,套件中是交給
系統開發者來決定,所以不能預設都是用UTF8String.....

然而在XE系列的ansiToUtf8( ) 函數中, 它的輸出有可能會是空字串(這說來話長,因為要做Client端 Request 解析)
, 若不用自己的函式,系統會出錯。

OK,其實我們的觀點是希望原廠在規劃這些實作時,能更有彈性一些,比方說,考量到一些舊有包袱的移轉,
這類的函數能有個Flag變數,讓設計人員可以自行決定;要不要自動轉換,而不是直接就自行轉換,立意雖好
但也造成困擾,因為沒有完全完美的方案,但希望至少程式人員有選擇如何處理的機會(不然,像有些與機器
的溝通有些與KeyPro的溝通,有些與舊式RS232設備的溝通,過程中資料被修改;那可是一件恐怖的事情)。

畢竟開發工具的投資是長長久久....大家的包袱只有越來越大....

感謝大大們的參與與回應,謝謝你們無私的付出;也希望大家再看這篇論述的過程中,得到一些想知道的知識。

以上



編輯記錄
JL9168 重新編輯於 2013-07-09 06:59:04, 註解 無‧
JL9168 重新編輯於 2013-07-09 07:01:32, 註解 無‧
Main Chen
高階會員


發表:29
回覆:134
積分:127
註冊:2002-10-07

發送簡訊給我
#21 引用回覆 回覆 發表時間:2013-07-09 13:35:14 IP:122.116.xxx.xxx 訂閱
這個討論串非常有參考價值, 之前 XE2 要轉 XE3 也遇到類似的問題, 程式碼在沒更動的情況下, 轉到 XE3 後, UTF8 相關的部份就是亂碼, 後來沒時間去追, 就讓它停留在 XE2 了.
ANDY8C
資深會員


發表:114
回覆:582
積分:299
註冊:2006-10-29

發送簡訊給我
#22 引用回覆 回覆 發表時間:2013-07-09 21:28:23 IP:60.248.xxx.xxx 未訂閱

您的想法我以前也提過,但這些大廠應該不會聽的......官大學問大

我以前曾提,STRING 宣告,不論到哪個版本,維持不變,都是 AnsiString (維持 D7 , D2007 那種舊格式)
但新版(XE,XE2,.....等) STRING 可以改用 XE_STRING 之類的宣告,才會變成 WideStribg 的格式
或者直接宣告 WideString 才是 Wide 功能,

這樣舊程式不就不用改了嗎??

===================引 用 JL9168 文 章===================

為何不用新的做法,道理也很簡單,因為每一次輸出網頁資料不一定都是使用UTF-8編碼,套件中是交給
系統開發者來決定,所以不能預設都是用UTF8String.....

然而在XE系列的ansiToUtf8( ) 函數中, 它的輸出有可能會是空字串(這說來話長,因為要做Client端 Request 解析)
, 若不用自己的函式,系統會出錯。

OK,其實我們的觀點是希望原廠在規劃這些實作時,能更有彈性一些,比方說,考量到一些舊有包袱的移轉,
這類的函數能有個Flag變數,讓設計人員可以自行決定;要不要自動轉換,而不是直接就自行轉換,立意雖好
但也造成困擾,因為沒有完全完美的方案,但希望至少程式人員有選擇如何處理的機會(不然,像有些與機器
的溝通有些與KeyPro的溝通,有些與舊式RS232設備的溝通,過程中資料被修改;那可是一件恐怖的事情)。

畢竟開發工具的投資是長長久久....大家的包袱只有越來越大....

感謝大大們的參與與回應,謝謝你們無私的付出;也希望大家再看這篇論述的過程中,得到一些想知道的知識。

以上



------
---------------------------------------
偶爾才來 KTOP ,交流條碼問題,在 FB [條碼標籤達人] 社團留言,感恩.
GrandRURU
站務副站長


發表:234
回覆:1651
積分:1742
註冊:2005-06-21

發送簡訊給我
#23 引用回覆 回覆 發表時間:2013-07-10 11:56:11 IP:59.120.xxx.xxx 訂閱
原廠表示:請用FireMonkey Framework,上述問題絕不復見!
===================引 用 ANDY8C 文 章===================

您的想法我以前也提過,但這些大廠應該不會聽的......官大學問大

我以前曾提,STRING 宣告,不論到哪個版本,維持不變,都是 AnsiString (維持 D7 , D2007 那種舊格式)
但新版(XE,XE2,.....等) STRING 可以改用 XE_STRING 之類的宣告,才會變成 WideStribg 的格式
或者直接宣告 WideString 才是 Wide 功能,

這樣舊程式不就不用改了嗎??
ANDY8C
資深會員


發表:114
回覆:582
積分:299
註冊:2006-10-29

發送簡訊給我
#24 引用回覆 回覆 發表時間:2013-07-10 15:22:43 IP:60.248.xxx.xxx 未訂閱
??  , 原廠如何說 ?? 

===================引 用 GrandRURU 文 章===================
原廠表示:請用FireMonkey Framework,上述問題絕不復見!

------
---------------------------------------
偶爾才來 KTOP ,交流條碼問題,在 FB [條碼標籤達人] 社團留言,感恩.
leveon
資深會員


發表:29
回覆:386
積分:303
註冊:2012-02-12

發送簡訊給我
#25 引用回覆 回覆 發表時間:2013-07-11 10:23:48 IP:61.228.xxx.xxx 訂閱
 這一篇很棒 讓人更加瞭解Delphi對Unicode支援的處理
之前剛試玩XE的時候 就發現string會自己轉碼 就猜想
string的結構上應該有類似codepage的東西
轉碼的實作應該也是利用作業系統的API去轉

個人認為目前新版Delphi 對string的處理是很合理的
舊Delphi應該就有想過要支援unicode 所以到處留下伏筆

如果再多一個型別出來
現有的VCL要全面支援unicode 會變的很困難

比較有問題的是在舊版Delphi寫Unicode程式的
轉到新Delphi可能會比較麻煩
RawByteString預設不填codepage 可以幫助debug
寫3rd的要支援新舊Delphi 可能要用編譯指令指示編譯
器編譯不同區段的Code會比較適當

至於上面說的firemonkey 還是IOS的支援
架構上 我認為Delphi做的不好 走錯了第一步
不過在這裡講這個可能會被攻堅
所以不討論了 顆顆


系統時間:2017-10-22 1:44:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!