Visual Basic for Applications (VBA) 代码与 Access Basic 代码相比较而言,其文本在内存中的存储格式是不同的。(Access Basic 曾经用在早期版本的 Microsoft Access 中。)Access Basic 代码中的文本以 ANSI 格式存储,而 Visual Basic 代码中的文本以 Unicode 格式存储。
Visual Basic 中使用的 Unicode 格式可以与 OLE 中文本的格式相匹配。OLE 间接地与 Visual Basic 相关。
例如,文本字符串“ABC”在内存中的存储如下所示:
存储格式 |
存储方式 |
说明 |
Unicode |
41 00 42 00 43 00 42 30 44 30 46 30 |
每个字符存为两个字节。 |
ANSI |
41 42 43 82 A0 82 A2 82 A4 |
ASCII 字符存为 1 个字节;双字节字符存为 2 个字节。 |
由于在内部格式上这些不同之处,在 Access Basic 和 Visual Basic 中字符串处理函数的运算也是有差异的。下面列出了这些运算有差异的函数及其语句。
Asc 函数、Chr 函数、InputB 函数、InStrB 函数、LeftB 函数、LenB 函数、RightB 函数、MidB 函数和相应的语句。
另外,Visual Basic 中又新增了 ChrB 函数和 AscB 函数。
由于这些函数和语句处理文本时均以字节为单位,所以它们在 Access Basic 和 Visual Basic 中是一样的。但因文本的存储格式不同,它们的运算是有差异的。例如,在 Access Basic 中 LenB("A") 为 1,而在 Visual Basic 中为 2。
早期版本的 Microsoft Access 中创建的程序若使用以字节为单位的字符串处理函数,在 Visual Basic 中必须变换成识别 Unicode 格式的源代码。但如果用到的仅是处理字符单位的字符串处理函数,如 Len 函数、Left 函数和 Right 函数等,则无需识别它们。
如果早期版本的 Microsoft Access 中创建的程序移植到当前版本的 Microsoft Access 中,则应考虑下列有关字符串处理的要点。
该程序在早期版本的 Access 中能正常运行,但在 Microsoft Access 中当前版本的 Visual Basic 中会产生运行时错误。
Print Asc(MidB("", 2,1))
这是因为 Asc 函数中的参数 MidB("", 2,1) 不能返回正确的 Unicode 格式文本数据。
用下面的 AscB 函数可以使该程序在当前版本的 Microsoft Access 中运行:
Print AscB(MidB("", 2,1))
在该程序中,返回了第二个 Unicode 格式字节的值 (&H30)。
Microsoft Access 中的 Chr 函数总是返回双字节字符。在早期版本的 Microsoft Access 中 Chr(&H41) 和 ChrB(&H41) 是相等的,而在当前版本的 Microsoft Access 中。Chr(&H41) 和 ChrB(&H41) + ChrB(0) 才是相等的。
同样,在早期版本的 Microsoft Access 中,“”表示为 ChrB(&H82) + ChrB(&HA0),但当前版本的 Microsoft Access 中却表示为 ChrB(&H42) + ChrB(&H30)。
在某些 Windows API 函数中,字符串的字节长度有特殊的含义。例如,下列程序返回一个在 Windows 中建立的文件夹。在 Microsoft Access 中,LeftB(Buffer, ret) 不能返回正确的字符串。这是因为尽管该函数显示了一个 ANSI 字符串的字节长度,但 LeftB 函数处理的却是 Unicode 字符串。在这种情况下可使用 InStr 函数只返回没有空值的字符串。
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 函数在将文本从文件读到一个 Unicode 格式字符串中时会转换指定数量的字符,并将其作为变量读取。而 InputB 函数却不然,它假定数据已是二进制,对其不加转换即存为变量。如果读取一个以固定长度字段存储的文件时使用 InputB 函数,那么该固定字节长度的数据一经读取便需转换。
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 格式字符串字节,可以使用 StrConv 函数。通过设置 vbUnicode 或 vbFromUnicode 常量可在 ANSI 和 Unicode 格式之间转换文本。如果在临时将一个 Unicode 格式字符串转换为 ANSI 格式字符串之后处理字节,处理完毕后又将其转换回 Unicode 格式,那么使用早期版本的 Access 中的代码要相对容易一些。
'
ANSI
dat = StrConv(dat, vbFromUnicode)
.
.
. '
. '
.
.
'
Unicode
dat = StrConv(dat, vbUnicode)
在 Visual Basic for Applications 中,字符串的内部处理使用 Unicode 格式。因此 VBA 中的二进制处理函数不同于 Access Basic 的二进制处理函数,Access Basic 曾经用在早期版本的 Microsoft Access 中。
ANSI 函数是为保持 Access Basic 和 Visual Basic 运算的兼容性而创建的。
注释 用这些 ANSI 处理函数输入和删除的字符串总是 Unicode 的。在函数中会临时转换为 ANSI 格式字符串,但处理过程一结束便将恢复 Unicode 格式。
下列代码不能将一个 DBCS 字符的第一和第二个字节合并而生成一个 DBCS 字符。
AnsiMidB("",1,1) + AnsiMidB("",2,1)
创建的这些函数以字节为单位处理字符串。但是通过这种以字节为单位的处理过程并不能生成不同的字符。在这种情况下,它将表达如下:
StrArg = ""
StrArg = StrConv(StrArg, vbFromUnicode) ' ANSI
RetArg = MidB(StrArg,1,1) + MidB(StrArg,2,1) '
'
StrArg = StrConv(StrArg, vbUnicode) ' Unicode
RetArg = StrConv(RetArg, vbUnicode) '
一般来说,如果在处理字符串之前将其转换成了 ANSI 字符,那么处理完毕后应将其恢复成 Unicode 字符。
字节字符串处理函数总是一个用于处理字符串的函数。若要处理二进制数据,可使用字节数组,而不要用字符串变量或字节字符串处理函数。
以字节“数组”形式存储的字符串如下所示:
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 数据类型已成为一种新增的数据类型。如果在处理二进制数据时使用了字符串变量类型,则文本将在 ANSI 和 Unicode 之间进行转换,并且将改变二进制数据。因此,处理二进制数据时应使用 Byte 数据类型的变量。
Dim ByteData() As Byte
ByteData = "" ' Unicode
ByteData = StrConv("", vbFromUnicode) 'ANSI
ByteData = InputB(10, #1) '
Debug.Print ByteData(5) '