【VBA研究】奇怪的“?”----Unicode格式的字元處理
1、從網站匯出的Excel檔案單元格內容後面多了一個不可見字元,怎麼造成的不知道,但不是每一列都有。想要用VBA程式碼去掉,就要先判斷出是什麼字元,將內容複製到文字環境中(比如程式設計環境或者UltraEdit中),發現最後面那個是個“?”,Asc()函式取其碼值也是63,但奇怪的是擷取這個字元和“?”或者Chr(63)相比,發現並不相等。
2、實際情況這個字元應該不是“?”,複製到記事本中,字元依然不可見,儲存檔案,提示包含Unicode字元(如下圖),如果繼續按ANSI編碼格式儲存,再開啟這個檔案發現最後面的那個字元就被轉換成了“?”。但如果按Unicode格式儲存,再開啟這個檔案則發現這個字元依然不可見,可見是原樣儲存的,用UltraEdit開啟檢視碼值,發現是0x00A0,即160。
3、想要去掉這個字元不是很難,因為我們匯出內容最後不會有“?”存在,所以用Asc()函式取值,只要是63,就去掉最後一個字元。如下:
If Asc(Right(MyRecord(j), 1)) = 63 Then MyRecord(j) = Left(MyRecord(j), Len(MyRecord(j)) - 1)
4、那麼這個字元到底是什麼呢?通過下面程式碼可以判斷其內碼值是160:
For kk = 1 To 65535
If Right(MyRecord(j), 1) = ChrW(kk) Then
MsgBox kk
End If
Next kk
注意:因為是不可見的Unicode字元,上面程式碼中ChrW(kk)如果寫成Chr(kk),那個條件則永遠不會成立,因為Chr(kk)返回的是ASCII字元,單位元組的。不過,如果左邊擷取的那個字元是ASCII字元,用Chr(kk)也是可以成立的。
上面的去掉不可見字元的語句寫成下面的就完美了:
If Right(MyRecord(j), 1) = ChrW(160) Then MyRecord(j) = Left(MyRecord(j), Len(MyRecord(j)) - 1)
5、為什麼這個碼值160的字元會被轉換成碼值63的“?”,研究了一下,發現在記事本中輸入碼值129以上的字元(Alt+小鍵盤數字)都會被認為是包含Unicode格式字元,按ANSI格式儲存後會轉換成“?”。在Windows記事本程式中,Unicode實際指的就是UTF-16。
6、上面內容涉及到檔案內容在記憶體中的編碼和儲存在硬碟中的編碼,實際上當我們開啟檔案時,系統會對檔案內容的編碼方式進行轉換,變成記憶體中的編碼格式。VBA對字串的編碼是Unicode方式,任何字元都是2位元組,但在做判斷時,又會根據情況確定是否轉換成ANSI方式。當說到一個字元的碼值時,首先要確定這個字元的編碼方式,上述碼值160只是這個字元的Unicode碼值。
==============================
附:Chr 函式
語法:Chr(charcode)
說明:返回 String,其中包含有與指定的字元程式碼相關的字元 。
必要的 charcode 引數是一個用來識別某字元的 Long。
0 到 31 之間的數字與標準的非列印 ASCII 程式碼相同。例如,Chr(10) 可以返回換行字元。charcode 的正常範圍為 0 – 255。然而,在 DBCS 系統,charcode 的實際範圍為 -32768 到 65535。
注意 ChrB 函式作用於包含在 String 中的位元組資料。ChrB 總是返回一個單位元組,而不是返回一個字元,一個字元可能是一個或兩個位元組。ChrW 函式返回包含 Unicode 的 String,若在不支援 Unicode 的平臺上,則其功能與 Chr 函式相同。
注意 Visual Basic for the Macintosh 不支援Unicode 字串。因此,當n 值在128 – 65,535 範圍內時, ChrW(n) 不能像在Windows環境中那樣返回所有的 Unicode 字元。相反地,當Unicode 的n 值大於127 時,ChrW(n) 會試圖做一個“最好的猜測”。因此,在Macintosh 環境中,不能使用ChrW 。
示例:
Dim MyChar
MyChar = Chr(65) ' 返回 A。
MyChar = Chr(97) ' 返回 a。
MyChar = Chr(62) ' 返回 >。
MyChar = Chr(37) ' 返回 %。
補充知識點:
要實現回車換行,我目前所知道的3種方法
VbNewline
VbCrLf
Chr(10)
補充:在Excel中,Char函式具有類似功能。