VB編程中的Unicode vs Ansi

VB編程中的Unicode vs Ansi
━━━━━━━━━━━━━━━━━━━━━━━━━━

作者:枕善居主

Unicode vs Ansi
Visual Basic 32 - bit 版本的字串處理採用 Unicode,也就是說字串在 VB 內部是以
Unicode 的格式來存放。

何謂 Unicode?簡單的說,就是每一個字元都是以 2 - Byte 的型式表示,而每個「實
體字元」就是一個「字元」。因此,

Len("大家好")
Len("abc")

所傳回的值都是 3,因爲「大」和「a」都是一個字元。

但是這對一些中文字串處理,例如純文字的資料檔,卻是一個大災難,因爲你必須以
Byte 來定位每個字元,可是 Unicode 卻把一切的處理全搞砸了。例如:

Len("Good Morning"傳回 12,而
Len("今天天氣很好"傳回 6

對初學者而言,好不容易能使用 VB 來寫程式已經是件了不起的事了,卻馬上在中文
處理上捱了一記悶棍,所受到的打擊實在不小。但是不要怕,事實上只要再多瞭解一
些指令,就可以把中文處理的問題解決了。

是什麼指令呢?最重要的莫過於 StrConv 了。StrConv 函式的語法爲:

StrConv(待轉換字串, 轉換格式)

其中轉換格式在這裏用到的是:

vbUnicode 將 Ansi 字串轉換爲 Unicode
vbFromUnicode 將 Unicode 字串轉換爲 Ansi

將字串轉成 Ansi 之後,所有的字串處理指令都要加個 B,例如:LeftB, RightB,
MidB, ChrB, InstrB, LenB, InputB 等。例用這些指令來處理就行了。

當你處理完畢之後,你可以再將它再轉回 Unicode,這樣就可以使用一般的字串處理
指令了。

這樣講看得懂嗎?如果還是不瞭解,看看下面的實例說明:

[●] 簡易使用範例

看看下面的基本範例您應該就會對 VB 的字串處理方式有些概念。

Private Sub Command1_Click ()
    
Dim sUnicode As String
    Dim 
sAnsi As String

    
' Unicode 運算
    
sUnicode "王小明,A123456789,651023,臺北市中山路100號,(02)2345678"
    Debug.Print Len(sUnicode' 傳回 44
    
Debug.Print Mid$(sUnicode, 5, 10' 傳回 A123456789
    
Debug.Print InStr(sUnicode, "臺北市"' 傳回 23

    ' 將 Unicode 字串轉成 Ansi
    
sAnsi StrConv(sUnicode, vbFromUnicode)
    
' Ansi 運算
    
Debug.Print LenB(sAnsi' 傳回 54
    
Debug.Print MidB$(sAnsi, 8, 10' 傳回 ?????,因爲忘了轉回 Unicode
    
Debug.Print StrConv(MidB$(sAnsi, 8, 10), vbUnicode' 傳回 A123456789,請注意轉回 Unicode 的動作一定要做
    
Debug.Print InStrB(sAnsi, StrConv("臺北市", vbFromUnicode)) ' 傳回 23, 不要忘了要把 "臺北市 "也轉成 Ansi,否則會找不到
End Sub

[
●] 讀入文字檔

在 VB 的小技巧中,有一個是快速讀檔法:

Private Sub Command1_Click ()
    
Dim sFile As String

    
Open "C:\filename.txtFor Input As #1
        sFile Input$(LOF(1), #1)
    
Close #1
End Sub

但是很不幸地,如果你讀取的檔案內含中文字,那上面這段程式會出現 Input past
End of file 的錯誤。因爲 LOF 傳回的是檔案的 Byte 數,而 Input 函式讀取的是
字元數,由於檔案內含中文,因此檔案中的字元數將會小於 Byte 數,於是就發生錯
誤了。

要解決這個問題,我們就要用到 StrConv 和 InputB 這兩個函式了:

Private Sub Command1_Click ()
    
Dim sFile As String

    
Open "C:\filename.txtFor Input As #1
        sFile StrConv(InputB$(LOF(1), #1), vbUnicode)
    
Close #1
End Sub

上面修正程式先用 InputB 將檔案讀進來,不過使用 InputB 所讀入的檔案是 Ansi
格式的,所以要再用 StrConv 轉成 Unicode 才行。

[●] 隨機資料檔

許多文字資料檔是以固定位元組的位置來加以區格,例如下面的資料格式:

王小民650110臺北市中山路100號 (02)1234567
張大呆660824花蓮縣大甲鎮廣東街23號(03)9876543
......

像這種類型的檔案要如何處理呢?這是就必須用到 Type 以及 Byte Array 了。

Private Type tagRecord
    Username(5As Byte ' 姓名 6 bytes
    
Birthday(5As Byte ' 生日 6 bytes
    
Address(21As Byte ' 地址 22 bytes
    
TEL(11As Byte ' 電話 12 bytes
    
CrLf(1As Byte ' 換列字元 2 bytes
End Type

Private Sub 
Command1_Click()
    
Dim uRecord As tagRecord

    Open "C:\filename.datFor Random As #Len LenB(uRecord)
        
Get #1, 2, uRecord ' 取第二筆資料

        
With uRecord ' With ... End With 應該會用吧
            
Debug.Print .Username ' 傳回 ???
            
Debug.Print StrConv(.Username, vbUnicode' 傳回  "張大呆 "
        
End With

    Close #
1
End Sub

在這個例子中,一定要用到 Byte array,因爲只有 Byte Array 才能正確地定位到每
個 Byte 的位置。以前使用字串來定位的方法已經不適用了,千萬要記住!但是使用
Byte Array 所讀入的資料是 Ansi 格式,若要處理或是做運算的話,記得還要轉成
Unicode 格式才行。

[●] 使用 Byte Array

除了上面必須使用 Byte 精確定位的例子之外,純文字的處理基本上是用不到 Byte
Array 的。byte Array 通常是用在處理 binary 資料。這方面的問題我們將另文討
論。

看吧!只要熟悉使用 StrConv,你就可以在 Unicode 及 Ansi 格式之間自由自在地變
來變去,相信當您看完這篇文章之後,對處理中文應該不再煩惱了吧!
返回

字符串中文的問題
字串中文的問題,起於vb的字串是使用UniCode,而我們一般是使用Ascii Code。

這差別在何處呢?UniCode的每個字元長度是2個byte,而Ascii是一個byte,

如果說,我將們將VB的字串寫入檔案,有時會有意想不到的結果。例如:

Text1.Text "這是一個abc" len5 Len(str5)
如果我們的Access資料庫有一欄位的長度是10個Byte,所以我們在TextBox中設定
MaxLength 10,但是上面的例子得到的len5是7,而不是我們認爲的11,因爲不管
是中文或英文,vb一律以UniCode來存,所以str5的長度是7個"字元",而text1最大
的長度限制是10,7沒有超過10,故使用者仍可輸入,但存檔時,11個byte超過10個byte,所以會有錯。
可是或許有人發現,使用RS232來傳資料時,另一端主機是Ascii編碼的機器,在vb中
我們若使用String來傳,一樣可以通啊,其實那是vb在傳送與接收data時,會做轉換
,使我們的程式設計較方便,但如果傳的資料是Binary時,就頭大啦。例如說,以字
串的方式來傳送資料,當想傳Ascii 大於128時,常有些問題,因爲ASC(Chr(129)) = 0
,使我們不能用Chr()的指令來放資料。(事實上,您可以使用ChrW(129)來存資料,
和使用AscW()來取得值,加個W代表是Word的運算),這時候,就只有使用Byte Array來做了。

1.UniCode轉成ByteAry

Dim byteAry() As Byte Dim str5 As String Dim As Long str5 "這abc"
byteAry str5 For LBound(byteAryTo UBound(byteAry)
Debug.Print byteAry(i'得 25 144 97 0 98 0 99 0 Next i
Debug.Print Len(str5), LenB(str5'得4 8
所以了,可看出UniCode 的特性,程式應改一下,使用Strconv()來轉換 Dim byteAry() As Byte
Dim str5 As String Dim As Long str5 "這abc"
byteAry StrConv(str5, vbFromUnicode)
For LBound(byteAryTo UBound(byteAry)
    
Debug.Print byteAry(i'得 25 144 97 98 99 Next i
    
Debug.Print LenB(StrConv(str5, vbFromUnicode)) '得5
    
2.ByteAry轉回UniCode 使用Strconv()轉換 Dim byteAry(10As Byte Dim Str5 As String
    
byteAry(0) = 25 byteAry(1) = 144 byteAry(2) = 97 byteAry(3) = 98
    byteAry(4) = 99 Str5 StrConv(byteAry, vbUniCode)3.一些有用的函式SubStr() 中文化取子字串,相對Mid()
    
Strlen() 中文化字串長度,相對Len()
    
StrLeft() 中文化取左字串,相對Left()
    
StrRight() 中文化取右字串,相對Right()
    
isChinese() Check某個字是否中文字

Public Function SubStr(ByVal tstr As String, start As Integer, Optional leng As VariantAs String
    Dim 
tmpstr As String
    If 
IsMissing(lengThen
        
tmpstr StrConv(MidB(StrConv(tstr, vbFromUnicode), start), vbUnicode)
    
Else
        
tmpstr StrConv(MidB(StrConv(tstr, vbFromUnicode), start, leng), vbUnicode)
    
End If
    
SubStr tmpstr
End Function


 Public Function 
Strlen(ByVal tstr As StringAs Integer
    
Strlen LenB(StrConv(tstr, vbFromUnicode))
End Function

Public Function 
StrLeft(ByVal str5 As String, ByVal len5 As LongAs String
    Dim 
tmpstr As String
    
tmpstr StrConv(str5, vbFromUnicode)
    
tmpstr LeftB(tmpstr, len5)
    
StrLeft StrConv(tmpstr, vbUnicode)
End Function

Public Function 
StrRight(ByVal str5 As String, ByVal len5 As LongAs String
    Dim 
tmpstr As String
    
tmpstr StrConv(str5, vbFromUnicode)
    
tmpstr RightB(tmpstr, len5)
    
StrLeft StrConv(tmpstr, vbUnicode)
End Function

Public Function 
isChinese(ByVal asciiv As IntegerAs Boolean
    
If Len(Hex$(asciiv)) > Then
        
isChinese True
    Else
        
isChinese False
    End If
End Function



    
混合字符串的長度
    在中文環境下,每個字被當做兩個 Byte 
    Len("漢1") = 2
    LenB("漢1") = 4
    但在許多情況下,我們希望中文字長度爲 2,英文字符爲 1。可用以下的函數:
    LenB(StrConv("漢1"), vbFormUnicode))


    清除字符串中指定的字符
    該函數在字符串 s 中清除 Search(注意:如果 s 爲 AAABBB,Search 爲 AB。如何?) :

Function StringCleaner(As String, Search As StringAs String
    Dim 
As Integer, res As String
    
res s
    Do While InStr(res, Search)
        
InStr(res, Search)
        
res Left(res, i 1) & Mid(res, i 1)
    
Loop
    
StringCleaner res
End Function



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章