字符串函数运算的差异

   

对用于 Microsoft Access 的 Visual Basic 和早期版本 Microsoft Access 的 Access Basic 来说,文本在内存中的存放格式是不同的。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 中,则应考虑下列有关字符串处理的要点。

Asc 函数和 AscB 函数

该程序在早期版本的 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)。

Chr 函数和 ChrB 函数

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 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

Input 函数和 InputB 函数

在 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 7.0 中处理 ANSI 格式字符串字节

如果必须在 Microsoft Access 中处理 ANSI 格式字符串字节,可以使用 StrConv 函数。通过设置 vbUnicodevbFromUnicode 常量可在 ANSI 和 Unicode 格式之间转换文本。如果在临时将一个 Unicode 格式字符串转换为 ANSI 格式字符串之后处理字节,处理完毕后又将其转换回 Unicode 格式,那么使用早期版本的 Access 中的代码要相对容易一些。

'  ANSI 
dat = StrConv(dat, vbFromUnicode)
.
.
.    ' 
.    ' 
.
.
'   Unicode 
dat = StrConv(dat, vbUnicode)

执行与 16 位字节处理函数相兼容的操作的示例函数

在 Microsoft Access Visual Basic for Applications 中,字符串的内部处理使用 Unicode 格式。因此不同于早期版本 Microsoft Access 中所用的 Access Basic 的二进制处理函数。

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

使用 Byte 数据类型

在 Microsoft Access 中,Byte 数据类型是一种新增的数据类型。如果在处理二进制数据时使用了字符串变量类型,则文本将在 ANSI 和 Unicode 之间进行转换,并且将改变二进制数据。因此,处理二进制数据时应使用 Byte 数据类型的变量。

Dim ByteData() As Byte
ByteData = ""        ' Unicode 
ByteData = StrConv("", vbFromUnicode)     'ANSI 
ByteData = InputB(10, #1)    ' 
Debug.Print ByteData(5)        '