Visual Basic for Applications (VBA) 代碼與 Access Basic 代碼相比較而言,其文本在內(nèi)存中的存儲(chǔ)格式是不同的。(Access Basic 曾經(jīng)用在早期版本的 Microsoft Access 中。)Access Basic 代碼中的文本以 ANSI 格式存儲(chǔ),而 Visual Basic 代碼中的文本以 Unicode 格式存儲(chǔ)。
Visual Basic 中使用的 Unicode 格式可以與 OLE 中文本的格式相匹配。OLE 間接地與 Visual Basic 相關(guān)。
例如,文本字符串“ABC”在內(nèi)存中的存儲(chǔ)如下所示:
存儲(chǔ)格式 |
存儲(chǔ)方式 |
說明 |
Unicode |
41 00 42 00 43 00 42 30 44 30 46 30 |
每個(gè)字符存為兩個(gè)字節(jié)。 |
ANSI |
41 42 43 82 A0 82 A2 82 A4 |
ASCII 字符存為 1 個(gè)字節(jié);雙字節(jié)字符存為 2 個(gè)字節(jié)。 |
由于在內(nèi)部格式上這些不同之處,在 Access Basic 和 Visual Basic 中字符串處理函數(shù)的運(yùn)算也是有差異的。下面列出了這些運(yùn)算有差異的函數(shù)及其語句。
Asc 函數(shù)、Chr 函數(shù)、InputB 函數(shù)、InStrB 函數(shù)、LeftB 函數(shù)、LenB 函數(shù)、RightB 函數(shù)、MidB 函數(shù)和相應(yīng)的語句。
另外,Visual Basic 中又新增了 ChrB 函數(shù)和 AscB 函數(shù)。
由于這些函數(shù)和語句處理文本時(shí)均以字節(jié)為單位,所以它們在 Access Basic 和 Visual Basic 中是一樣的。但因文本的存儲(chǔ)格式不同,它們的運(yùn)算是有差異的。例如,在 Access Basic 中 LenB("A") 為 1,而在 Visual Basic 中為 2。
早期版本的 Microsoft Access 中創(chuàng)建的程序若使用以字節(jié)為單位的字符串處理函數(shù),在 Visual Basic 中必須變換成識(shí)別 Unicode 格式的源代碼。但如果用到的僅是處理字符單位的字符串處理函數(shù),如 Len 函數(shù)、Left 函數(shù)和 Right 函數(shù)等,則無需識(shí)別它們。
如果早期版本的 Microsoft Access 中創(chuàng)建的程序移植到當(dāng)前版本的 Microsoft Access 中,則應(yīng)考慮下列有關(guān)字符串處理的要點(diǎn)。
該程序在早期版本的 Access 中能正常運(yùn)行,但在 Microsoft Access 中當(dāng)前版本的 Visual Basic 中會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。
Print Asc(MidB("", 2,1))
這是因?yàn)?Asc 函數(shù)中的參數(shù) MidB("", 2,1) 不能返回正確的 Unicode 格式文本數(shù)據(jù)。
用下面的 AscB 函數(shù)可以使該程序在當(dāng)前版本的 Microsoft Access 中運(yùn)行:
Print AscB(MidB("", 2,1))
在該程序中,返回了第二個(gè) Unicode 格式字節(jié)的值 (&H30)。
Microsoft Access 中的 Chr 函數(shù)總是返回雙字節(jié)字符。在早期版本的 Microsoft Access 中 Chr(&H41) 和 ChrB(&H41) 是相等的,而在當(dāng)前版本的 Microsoft Access 中。Chr(&H41) 和 ChrB(&H41) + ChrB(0) 才是相等的。
同樣,在早期版本的 Microsoft Access 中,“”表示為 ChrB(&H82) + ChrB(&HA0),但當(dāng)前版本的 Microsoft Access 中卻表示為 ChrB(&H42) + ChrB(&H30)。
在某些 Windows API 函數(shù)中,字符串的字節(jié)長度有特殊的含義。例如,下列程序返回一個(gè)在 Windows 中建立的文件夾。在 Microsoft Access 中,LeftB(Buffer, ret) 不能返回正確的字符串。這是因?yàn)楸M管該函數(shù)顯示了一個(gè) ANSI 字符串的字節(jié)長度,但 LeftB 函數(shù)處理的卻是 Unicode 字符串。在這種情況下可使用 InStr 函數(shù)只返回沒有空值的字符串。
Private Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, _
ByVal nSize As Long) As Long
Private Sub Command1_Click()
Buffer$ = Space(255)
ret = GetWindowsDirectory(Buffer$, 255)
' WinDir = LeftB(Buffer, ret) '<--- Incorrect code"
WinDir = Left(Buffer$, InStr(Buffer$, Chr(0)) - 1)
'<--Correct code"
Print WinDir
End Sub
在 Microsoft Access 中,Input 函數(shù)在將文本從文件讀到一個(gè) Unicode 格式字符串中時(shí)會(huì)轉(zhuǎn)換指定數(shù)量的字符,并將其作為變量讀取。而 InputB 函數(shù)卻不然,它假定數(shù)據(jù)已是二進(jìn)制,對其不加轉(zhuǎn)換即存為變量。如果讀取一個(gè)以固定長度字段存儲(chǔ)的文件時(shí)使用 InputB 函數(shù),那么該固定字節(jié)長度的數(shù)據(jù)一經(jīng)讀取便需轉(zhuǎn)換。
Open "Data.Dat" For Input As 1
dat1 = StrConv(InputB(10, 1), vbUnicode)
dat2 = StrConv(InputB(10, 1), vbUnicode)
dat3 = StrConv(InputB(10, 1), vbUnicode)
===DATA.DAT
123456789012345678901234567
Name Address Telephone
如果必須在 Microsoft Access 中處理 ANSI 格式字符串字節(jié),可以使用 StrConv 函數(shù)。通過設(shè)置 vbUnicode 或 vbFromUnicode 常量可在 ANSI 和 Unicode 格式之間轉(zhuǎn)換文本。如果在臨時(shí)將一個(gè) Unicode 格式字符串轉(zhuǎn)換為 ANSI 格式字符串之后處理字節(jié),處理完畢后又將其轉(zhuǎn)換回 Unicode 格式,那么使用早期版本的 Access 中的代碼要相對容易一些。
'
ANSI
dat = StrConv(dat, vbFromUnicode)
.
.
. '
. '
.
.
'
Unicode
dat = StrConv(dat, vbUnicode)
在 Visual Basic for Applications 中,字符串的內(nèi)部處理使用 Unicode 格式。因此 VBA 中的二進(jìn)制處理函數(shù)不同于 Access Basic 的二進(jìn)制處理函數(shù),Access Basic 曾經(jīng)用在早期版本的 Microsoft Access 中。
ANSI 函數(shù)是為保持 Access Basic 和 Visual Basic 運(yùn)算的兼容性而創(chuàng)建的。
注釋 用這些 ANSI 處理函數(shù)輸入和刪除的字符串總是 Unicode 的。在函數(shù)中會(huì)臨時(shí)轉(zhuǎn)換為 ANSI 格式字符串,但處理過程一結(jié)束便將恢復(fù) Unicode 格式。
下列代碼不能將一個(gè) DBCS 字符的第一和第二個(gè)字節(jié)合并而生成一個(gè) DBCS 字符。
AnsiMidB("",1,1) + AnsiMidB("",2,1)
創(chuàng)建的這些函數(shù)以字節(jié)為單位處理字符串。但是通過這種以字節(jié)為單位的處理過程并不能生成不同的字符。在這種情況下,它將表達(dá)如下:
StrArg = ""
StrArg = StrConv(StrArg, vbFromUnicode) ' ANSI
RetArg = MidB(StrArg,1,1) + MidB(StrArg,2,1) '
'
StrArg = StrConv(StrArg, vbUnicode) ' Unicode
RetArg = StrConv(RetArg, vbUnicode) '
一般來說,如果在處理字符串之前將其轉(zhuǎn)換成了 ANSI 字符,那么處理完畢后應(yīng)將其恢復(fù)成 Unicode 字符。
字節(jié)字符串處理函數(shù)總是一個(gè)用于處理字符串的函數(shù)。若要處理二進(jìn)制數(shù)據(jù),可使用字節(jié)數(shù)組,而不要用字符串變量或字節(jié)字符串處理函數(shù)。
以字節(jié)“數(shù)組”形式存儲(chǔ)的字符串如下所示:
Array
Dim Var() As Byte
Var = "" ' Unicode
Var = StrConv("", vbFromUnicode) ' ANSI
Function AnsiStrConv(StrArg, flag)
nsiStrConv = StrConv(StrArg, flag)
End Function
' LenB ANSI
Unicode
Function AnsiLenB(ByVal StrArg As String) As Long
AnsiLenB = LenB(AnsiStrConv(StrArg, vbFromUnicode))
End Function
' MidB ANSI
Unicode
'
Function AnsiMidB(ByVal StrArg As String, ByVal arg1 As Long, _
Optional arg2) As String
If IsMissing(arg2) Then
AnsiMidB = AnsiStrConv(MidB(AnsiStrConv(StrArg, vbFromUnicode) _
, arg1),vbUnicode)
Else
AnsiMidB = AnsiStrConv(MidB(AnsiStrConv(StrArg, vbFromUnicode) _
, arg1, arg2), vbUnicode)
End If
End Function
' LeftB
ANSI
Unicode
Function AnsiLeftB(ByVal StrArg As String, ByVal arg1 As Long) As String
AnsiLeftB = AnsiStrConv(LeftB(AnsiStrConv(StrArg, _
vbFromUnicode), arg1), vbUnicode)
End Function
' RightB ANSI
Unicode
Function AnsiRightB(ByVal StrArg As String, ByVal arg1 As Long) As String
AnsiRightB = AnsiStrConv(RightB(AnsiStrConv(StrArg, _
vbFromUnicode), arg1), vbUnicode)
End Function
' InStrB 2 Ansi Ansi
Function AnsiInStrB(arg1, arg2, Optional arg3) As Integer
If IsNumeric(arg1) Then
pos = LenB(AnsiLeftB(arg2, arg1))
AnsiInStrB = InStrB(arg1, AnsiStrConv(arg2, vbFromUnicode) _
, AnsiStrConv(arg3, vbFromUnicode))
Else
AnsiInStrB = InStrB(AnsiStrConv(arg1, vbFromUnicode) _
, AnsiStrConv(arg2, vbFromUnicode))
End If
End Function
在 Microsoft Access 中,Byte 數(shù)據(jù)類型已成為一種新增的數(shù)據(jù)類型。如果在處理二進(jìn)制數(shù)據(jù)時(shí)使用了字符串變量類型,則文本將在 ANSI 和 Unicode 之間進(jìn)行轉(zhuǎn)換,并且將改變二進(jìn)制數(shù)據(jù)。因此,處理二進(jìn)制數(shù)據(jù)時(shí)應(yīng)使用 Byte 數(shù)據(jù)類型的變量。
Dim ByteData() As Byte
ByteData = "" ' Unicode
ByteData = StrConv("", vbFromUnicode) 'ANSI
ByteData = InputB(10, #1) '
Debug.Print ByteData(5) '