字符串函数运算的差异

Visual Basic for Applications (VBA) 代码与 Access Basic 代码相比较而言,其文本在内存中的存储格式是不同的。(Access Basic 曾经用在早期版本的 Microsoft Access 中。)Access Basic 代码中的文本以 ANSI 格式存储,而 Visual Basic 代码中的文本以 Unicode 格式存储。

Visual Basic 中使用的 Unicode 格式可以与 OLE 中文本的格式相匹配。OLE 间接地与 Visual Basic 相关。

例如,文本字符串“ABCfe140fe086fe228”在内存中的存储如下所示:

存储格式

存储方式

说明

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("fe140", 2,1))

这是因为 Asc 函数中的参数 MidB("fe140", 2,1) 不能返回正确的 Unicode 格式文本数据。

用下面的 AscB 函数可以使该程序在当前版本的 Microsoft Access 中运行:

Print AscB(MidB("fe140", 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 中,“fe140”表示为 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 中的代码要相对容易一些。

'fe141fe141fe087

   fe143fe144fe145fe146fe147fe019fe148fe149fe150fe095fe089fe095fe153fe154fe019fe155fe156fe157fe158fe160fe161fe150

ANSI fe163fe164fe165fe160fe166fe231fe093fe095fe232

dat = StrConv(dat, vbFromUnicode)

.

.

.    'fe141fe141fe087

   fe143fe144fe145fe146fe147fe019fe148fe149fe150fe167fe086fe093fe095fe232

.    'fe016fe084fe231

fe169fe170fe019fe155fe156fe146fe147fe019fe155fe156fe157fe158fe148fe149fe090fe087fe009fe093fe172fe173fe232

.

.

fe141fe141fe087

   fe143fe144fe145fe146fe147fe019fe148fe149fe150fe095fe089fe095fe153fe154fe019fe155fe156fe157fe158fe174fe161fe150

Unicode fe163fe164fe165fe160fe166fe231fe093fe095fe232

dat = StrConv(dat, vbUnicode)

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

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

ANSI 函数是为保持 Access Basic 和 Visual Basic 运算的兼容性而创建的。

注释  用这些 ANSI 处理函数输入和删除的字符串总是 Unicode 的。在函数中会临时转换为 ANSI 格式字符串,但处理过程一结束便将恢复 Unicode 格式。

下列代码不能将一个 DBCS 字符的第一和第二个字节合并而生成一个 DBCS 字符。

AnsiMidB("fe140",1,1) + AnsiMidB("fe140",2,1)

创建的这些函数以字节为单位处理字符串。但是通过这种以字节为单位的处理过程并不能生成不同的字符。在这种情况下,它将表达如下:

StrArg = "fe140"

StrArg = StrConv(StrArg, vbFromUnicode)    ' ANSI fe165fe160fe166

RetArg = MidB(StrArg,1,1) + MidB(StrArg,2,1)    ' fe143fe144fe145fe146fe147fe019fe155fe156fe157fe158

   ' fe175fe176

StrArg = StrConv(StrArg, vbUnicode)    ' fe177fe178fe235fe181fe182fe161fe150 Unicode fe165

RetArg = StrConv(RetArg, vbUnicode)    ' fe160fe166fe095fe089fe232

一般来说,如果在处理字符串之前将其转换成了 ANSI 字符,那么处理完毕后应将其恢复成 Unicode 字符。

字节字符串处理函数总是一个用于处理字符串的函数。若要处理二进制数据,可使用字节数组,而不要用字符串变量或字节字符串处理函数。

以字节“数组”形式存储的字符串如下所示:

fe143fe144fe145

Array fe165

fe155fe156fe157fe158fe150fe184fe185fe095fe089fe186fe187fe090

   fe188fe019fe229fe230fe165fe231fe093fe095fe232

Dim Var() As Byte

Var = "fe189fe156fe019fe191fe192fe193"             ' Unicode fe163fe164fe087fe184fe185

Var = StrConv("fe189fe156fe019fe191fe192fe193", vbFromUnicode)    ' ANSI fe163fe164fe087fe184fe185

Function AnsiStrConv(StrArg, flag)

   nsiStrConv = StrConv(StrArg, flag)

End Function

' LenB fe087fe175fe176fe095fe089fe199fe165ANSI fe155fe156fe157fe158fe165fe160fe166fe231fe233

   fe175fe176fe177fe178fe150

Unicode fe165fe174fe231fe093fe095fe232

Function AnsiLenB(ByVal StrArg As String) As Long

   AnsiLenB = LenB(AnsiStrConv(StrArg, vbFromUnicode))

End Function

' MidB fe087fe175fe176fe095fe089fe199fe165fe233ANSI fe155fe156fe157fe158fe165fe160fe166fe231fe233fe233

   fe175fe176fe177fe178fe150

Unicode fe165fe174fe231fe093fe095fe232

fe201fe202fe226fe227fe205fe181fe182fe161fe150fe208fe209fe210fe112fe231fe154fe211fe081fe224fe182fe161fe150fe213fe214fe231fe093fe095fe232

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 fe087fe175fe176fe095fe089fe199fe165fe233

ANSI fe155fe156fe157fe158fe165fe160fe166fe231fe233fe233

   fe175fe176fe177fe178fe150

Unicode fe165fe174fe231fe093fe095fe232

Function AnsiLeftB(ByVal StrArg As String, ByVal arg1 As Long) As String

   AnsiLeftB = AnsiStrConv(LeftB(AnsiStrConv(StrArg, _

           vbFromUnicode), arg1), vbUnicode)

End Function

' RightB fe087fe175fe176fe095fe089fe199fe165fe233ANSI fe155fe156fe157fe158fe165fe160fe166fe231fe233fe233

   fe175fe176fe177fe178fe150

Unicode fe165fe174fe231fe093fe095fe232

Function AnsiRightB(ByVal StrArg As String, ByVal arg1 As Long) As String

   AnsiRightB = AnsiStrConv(RightB(AnsiStrConv(StrArg, _

           vbFromUnicode), arg1), vbUnicode)

End Function

' InStrB fe019 2 fe215fe019fe155fe156fe157fe158fe181fe182fe161fe165fe233 Ansi fe155fe156fe157fe158fe235fe233Ansi fe143fe144fe145fe147fe216fe150fe181fe182fe009fe218fe231fe093fe095fe232

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 = "fe155fe156fe157fe158"        ' Unicode fe163fe164fe087fe184fe185fe085fe221fe093fe095fe232

ByteData = StrConv("fe155fe156fe157fe158", vbFromUnicode)     'ANSI fe163fe164fe087fe184fe185fe085fe221fe093fe095fe232

ByteData = InputB(10, #1)    'fe143fe144fe145fe222

fe191fe192fe193fe236fe184fe185fe085fe221fe093fe095fe232

Debug.Print ByteData(5)        'fe223fe224fe157fe158fe235fe231fe154fe191fe192fe193fe150fe148fe149fe226fe227fe087fe095fe232