字串中文的問題
字串中文的問題,起於vb的字串是使用UniCode,而我們一般是使用Ascii Code。
這差別在何處呢?UniCode的每個(gè)字元長度是2個(gè)byte,而Ascii是一個(gè)byte,如果
說,我將們將VB的字串寫入檔案,有時(shí)會有意想不到的結(jié)果。例如:
Text1.Text = "這是一個(gè)abc"
len5 = Len(str5)
如果我們的Access資料庫有一欄位的長度是10個(gè)Byte,所以我們在TextBox中設(shè)定
MaxLength = 10,但是上面的例子得到的len5是7,而不是我們認(rèn)為的11,因?yàn)椴还?br />是中文或英文,vb一律以UniCode來存,所以str5的長度是7個(gè)"字元",而text1最大
的長度限制是10,7沒有超過10,故使用者仍可輸入,但存檔時(shí),11個(gè)byte超過10個(gè)
byte,所以會有錯(cuò)。
可是或許有人發(fā)現(xiàn),使用RS232來傳資料時(shí),另一端主機(jī)是Ascii編碼的機(jī)器,在vb中
我們?nèi)羰褂肧tring來傳,一樣可以通啊,其實(shí)那是vb在傳送與接收data時(shí),會做轉(zhuǎn)換
,使我們的程式設(shè)計(jì)較方便,但如果傳的資料是Binary時(shí),就頭大啦。例如說,以字
串的方式來傳送資料,當(dāng)想傳Ascii 大於128時(shí),常有些問題,因?yàn)锳SC(Chr(129))=0
,使我們不能用Chr()的指令來放資料。(事實(shí)上,您可以使用ChrW(129)來存資料,
和使用AscW()來取得值,加個(gè)W代表是Word的運(yùn)算),這時(shí)候,就只有使用Byte Array
來做了。
1.UniCode轉(zhuǎn)成ByteAry
Dim byteAry() As Byte
Dim str5 As String
Dim i As Long
str5 = "這abc"
byteAry = str5
For i = LBound(byteAry) To 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 的特性,程式應(yīng)改一下,使用Strconv()來轉(zhuǎn)換
Dim byteAry() As Byte
Dim str5 As String
Dim i As Long
str5 = "這abc"
byteAry = StrConv(str5, vbFromUnicode)
For i = LBound(byteAry) To UBound(byteAry)
Debug.Print byteAry(i) '得 25 144 97 98 99
Next i
Debug.Print LenB(StrConv(str5, vbFromUnicode)) '得5
2.ByteAry轉(zhuǎn)回UniCode 使用Strconv()轉(zhuǎn)換
Dim byteAry(10) as 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() |
將阿拉伯?dāng)?shù)字轉(zhuǎn)成中文字的程式
一個(gè)Form
一個(gè)TextBox
一個(gè)Label
這個(gè)修訂後的程式是當(dāng)使用者在TextBox中輸入只包含 0~9 的數(shù)值後,在Label中就可
看見被轉(zhuǎn)換後的中文字,例如:1560890 轉(zhuǎn)成 "壹佰伍拾陸萬零捌佰玖拾"。程式限制
為不可輸入超過16個(gè)數(shù)字。
請建立一個(gè)新專案,并在表單中放入上述物件,再把以下程式碼復(fù)制到表單的程式
碼視窗,最後按下F5來執(zhí)行。
Private Sub Form_Load()
Text1.MaxLength = 16
Text1.Text = ""
Label1.Caption = ""
Label1.AutoSize = True
Label1.BorderStyle = 1
End Sub
Private Sub Text1_Change()
Label1.Caption = CChinese(Text1.Text)
End Sub
Private Function CChinese(StrEng As String) As String
If Not IsNumeric(StrEng) Or StrEng Like "*.*" Or StrEng Like "*-*" Then
If Trim(StrEng) <> "" Then MsgBox "無效的數(shù)字"
CChinese = "": Exit Function
End If
Dim intLen As Integer, intCounter As Integer
Dim strCh As String, strTempCh As String
Dim strSeqCh1 As String, strSeqCh2 As String
Dim strEng2Ch As String
strEng2Ch = "零壹貳叁肆伍陸柒捌玖"
strSeqCh1 = " 拾佰仟 拾佰仟 拾佰仟 拾佰仟"
strSeqCh2 = " 萬億兆"
StrEng = CStr(CDec(StrEng))
intLen = Len(StrEng)
For intCounter = 1 To intLen
strTempCh = Mid(strEng2Ch, Val(Mid(StrEng, intCounter, 1)) + 1, 1)
If strTempCh = "零" And intLen <> 1 Then
If Mid(StrEng, intCounter + 1, 1) = "0" Or (intLen - intCounter + 1) Mod 4 = 1 Then
strTempCh = ""
End If
Else
strTempCh = strTempCh & Trim(Mid(strSeqCh1, intLen - intCounter + 1, 1))
End If
If (intLen - intCounter + 1) Mod 4 = 1 Then
strTempCh = strTempCh & Mid(strSeqCh2, (intLen - intCounter + 1) \ 4 + 1, 1)
If intCounter > 3 Then
If Mid(StrEng, intCounter - 3, 4) = "0000" Then strTempCh = Left(strTempCh, Len(strTempCh) - 1)
End If
End If
strCh = strCh & Trim(strTempCh)
Next
CChinese = strCh
End Function
在VB中使用枚舉變量 |
VB5 引入枚舉變量,使用它,我們可以顯著地改變應(yīng)用程序的易讀性: Public Enum TimeOfDay Morning = 0 Afternoon = 1 Evening = 2 End Enum Sub Main() Dim RightNow As TimeOfDay If Time >= #12:00:00 AM# And Time <#12:00:00 PM# Then RightNow = Morning ElseIf Time >= #12:00:00 PM# And Time <#6:00:00 PM# Then RightNow = Afternoon ElseIf Time >= #6:00:00 PM# Then RightNow = Evening End If End Sub |
VB編程技巧幾例 山東 許振華 |
1 文本框內(nèi)容的自動選擇。 在軟件安裝等一些場合需要將文本框中的內(nèi)容自動選擇,比如選擇確省安裝路徑,在VB中可用如下的事件驅(qū)動代碼: sub text1_getfocus() text1.selstart=0 ’選擇起始位置 text1.sellength=65000 ’選擇長度 end sub sellength接近文本框允許的最大長度(65535),這樣做是為了 強(qiáng)迫VB使用文本的實(shí)際長度。 2 防止自身多次運(yùn)行。 由于WINDOWS的多任務(wù)處理功能, 有些程序可能打開后忘記了,下次用時(shí)還可能再打開,這樣做會占用系統(tǒng)資源降低系統(tǒng)效率。為了防止自身被多次運(yùn)行,可利用VB應(yīng)用對象提供的PrevInstance屬性來檢測內(nèi)存中是否已有一個(gè)自身的副本,若有則給出提示后結(jié)束。一般將檢測代碼放在FORM_LOAD()中,因?yàn)槌绦蛞贿\(yùn)行就要檢測。 代碼如下: sub form_load() if App.PrevInstance then msg$=App.exename & ”has already run” msgbox msg$,48 ’給出程序已運(yùn)行的提示和一驚嘆號以示警告 end endif end sub 3 格式化輸入。 在數(shù)據(jù)輸入過程中,有些數(shù)據(jù)要求一定的格式,比如限制輸入的只能為數(shù)字或英文字符,這可用VB的格式輸入文本框來實(shí)現(xiàn)。它與文本框(TEXT BOX)功能基本相似,但多了一個(gè)MASK屬性,MASK屬性常用的設(shè)定如下: #?限定僅能輸入數(shù)字0~9; A? 限定輸入為英文字符及數(shù)字; ??限定僅能輸入英文字符; .?限定小數(shù)點(diǎn)位置; :?限定時(shí)間分隔號; /?限定日期分隔號 不需編寫代碼,只要在設(shè)計(jì)時(shí)將格式化文本框?qū)ο螅∕ASKED EDIT)的MASK屬性設(shè)計(jì)好所需格式即可。比如 ## - ## - ## 可輸入12-11-96。 4 用MSGBOX函數(shù)設(shè)計(jì)版權(quán)信息。 MsgBox函數(shù)可用來設(shè)計(jì)簡易的版權(quán)信息,它只能顯示文本,如果要求不高的話可采用它,優(yōu)點(diǎn)是非常方便,比如在菜單ABOUT項(xiàng)中顯示版權(quán)信息。 MsgBox函數(shù)的用法如下:MsgBox msg [, [type][, title] ] msg ?需要顯示的文字信息,如版權(quán)信息。 type?按鈕顯示選擇項(xiàng)。 如 0 只顯示 OK按鈕(確省選擇),4 顯示 Yes 和 No 按鈕 title?標(biāo)題文字信息。 MSGBOX最多能顯示1024個(gè)字符, 超出的將被截去;它可自動換行,如果你想強(qiáng)制換行的話需要在換行處加入換行符CHR(10)。 例子: Sub Form_Click () Msg1 = ” Copyright (c) 1996” & Chr(10) & ”Ver 1.0 ” ’分兩行顯示 MsgBox Msg1, 0, ”Copyright demo” ’只顯示一個(gè)OK按鈕 End Sub |
使用 IIF 和 SWITCH 以精減代碼 |
在很多地方你都可以使用一個(gè)更緊湊的 IIf 函數(shù)來代替 If...Else...Endif 的結(jié)構(gòu): 例:返回兩個(gè)值中較大的一個(gè) maxValue = IIf(first >= second, first, second) Switch 則是一個(gè)很少使用的函數(shù),可是在很多方面它都提供比 If...ElseIf 結(jié)構(gòu)更好的 例:判斷 "x" 是正、負(fù)還是 null? Print Switch(x<0,"負(fù)",x>0,"正", True, "Null") |
變量的地址 |
VB5 內(nèi)置了一個(gè) VarPtr 函數(shù),可是此函數(shù)在 VB4 中沒有提供??墒悄阒绬??VB4 的運(yùn)行庫中已經(jīng)包含了此函數(shù)。只是在用它之前,我們需要聲明一下: #If Win16 Then Declare Function VarPtr Lib "VB40016.DLL" (variable As Any) As Long #Else Declare Function VarPtr Lib "VB40032.DLL" (variable As Any) As Long #End If 此函數(shù)在傳遞一個(gè) Type 結(jié)構(gòu)(如果此結(jié)構(gòu)要求其一段是另一個(gè)變量或記錄的地址)給一個(gè)外部的 API 程序時(shí)十分有用。 |
向文件中寫入非 ASCII 字符 |
如何向一個(gè)文件中寫入非ASCII字符(ASCII碼在128-255之間)?這在 VB3 中按常規(guī)方法就可以很好處理。但是,自 VB4 起,微軟引入 Unicode 后,此問題就顯得有些麻煩。方法如下: Dim a As Byte '如果你不用 Unicode,微軟推薦使用 Byte 類型替換 String 類型 a=&HF5 '此處直接給處 ASCII 碼即可 Open "test.dat" For Binary As #1 Put #1, , a Close (1) |
VB中感嘆號“!”與圓點(diǎn)“.”的用法差異 河北 馬昱 |
在Visual Basic中,驚嘆號“!”與圓點(diǎn)“.”都用于給對象命名,但兩者語法上卻存在很大的區(qū)別,這點(diǎn)在編程時(shí)尤其需要注意。 圓點(diǎn)操作符“.”用來表示對象的屬性和方法,在引用時(shí),需要用到對象的Name、圓點(diǎn)和需要的屬性或方法。例如要引用文本框Textl中的文本屬性時(shí)可用reponse$=Text1.Text,再如要改變Form1窗體返回或讀取對象高度的單位時(shí)用Form1.ScaleHeigh=2000表示。 感嘆號“!”常用于當(dāng)一個(gè)控件作為一個(gè)特性訪問的情況下,例如引用Fomr2中Text1文本框文本屬性時(shí),可采用response$=Form2!text1.text語法格式。 雖然兩者的語法應(yīng)用結(jié)構(gòu)有較大差異,但兩條語句的性能是相同的,值得注意的是如果你在感嘆號“!”的位置使用“.”可以獲得對窗體上Text1特性的直接訪問權(quán),為了進(jìn)一步增加感性認(rèn)識,你不妨運(yùn)行下面的例子來試試。 1.建立一個(gè)新項(xiàng)目,并在Form1窗體中增加一個(gè)命令控件。 2.雙擊Form1窗體,編輯Form-Load事件并輸入: Form1!Com?mand1.Caption=”Text” Form1.Command1.Caption=”It Works” 3.運(yùn)行試項(xiàng)目,這時(shí)你就會在Command1命令框中看到字符串It Works。 為了在程序中清楚地界定引用的控件名和該控件的屬性或方法,增加程序的可讀性,最好使用感嘆號“!”,這也是VB的推薦方式。 |
0、""(空字串)、Null、Empty、與 Nothing 的區(qū)別 |
先回答以下問題吧! 經(jīng)過以下的敘述之后, 變量 A、B、C、D 分別等于 0、""、Null、 Empty、 Nothing 的哪一個(gè)? Dim A Dim B As String Dim C As Integer Dim D As Object A 等于 Empty, 因?yàn)樯形闯跏蓟摹覆欢ㄐ妥兞俊苟嫉扔?Empty。但如果檢測 A = "" 或 A = 0, 也都可以得到 True 值。 B 等于 "", 因?yàn)樯形闯跏蓟姆枪潭ㄩL度「字串」都等于 "" 。 但請注意 B<> Null。 C 等于 0, 這個(gè)還有問題嗎? D 等于 Nothing, 尚未設(shè)定有物件的「物件變量」都等于 Nothing, 但請不要使用 D = Nothing , 而要使用 D Is Nothing 來判斷 D 是否等于 Nothing, 因?yàn)榕袛?是否相等的符號是 Is 不是 = 。 最令人迷惑的地方是 Null 這個(gè)保留字, 請看以下語句: Print X = Null Print X <> Null 結(jié)果都是輸出 Null(不是 True 也不是 False), 這是因?yàn)槿魏我粋€(gè)運(yùn)算式只要含有 Null , 則該運(yùn)算式就等于 Null, 實(shí)際上想要判斷某一數(shù)據(jù)是否為 Null 絕對不能使用: If X = Null Then ' 永遠(yuǎn)都會得到 Null 而要使用: If IsNull(X) Then 哪一種數(shù)據(jù)會等于 Null 呢? 除了含有 Null 運(yùn)算式之外, 就屬沒有輸入任何數(shù)據(jù)的「數(shù)據(jù)字段」(在數(shù)據(jù)庫中) 會等于 Null。 |
巧用Visual Basic的RND()函數(shù) 浙江 傅昌盛 |
Visual Basic的RND()函數(shù)有一個(gè)重要的特征:當(dāng)RND()的參數(shù)(我們稱這里可以稱它為種子)為負(fù)值時(shí),同一種子(負(fù)值)產(chǎn)生同一個(gè)隨機(jī)數(shù)序列。同時(shí)Visual Basic還具有強(qiáng)大的二進(jìn)制技術(shù)功能,這樣我們可以按以下思路實(shí)現(xiàn)文件內(nèi)容加密: X=RND(-KEY) ’KEY為正數(shù) VAULE=INT(256*RND) ’產(chǎn)生一個(gè)隨機(jī)數(shù)(以此為密碼) Open FILENAME$ For Binary As #FILENUM’打開文件 Get #FILENUM,I,A ’取文件內(nèi)容 B=A XOR VAULE ’得到加密文件 結(jié)合 C=B XOR VAULE’得到解密文件(B為加密后文件內(nèi)容) 注意:這里的A非整個(gè)文件內(nèi)容,可以是極少部分、幾個(gè)字節(jié)甚至單個(gè)字節(jié),若為單字節(jié),則文件中的每個(gè)字節(jié)同不同的數(shù)異或,破譯難度可見有多么大。具體過程: Sub ENDECODE(FILENAME$,MA,FILE2$)'參數(shù)為:源文件,密碼,目標(biāo)文件 Dim FILENUM As Integer,X As Single,I As Single Dim CHARNUM As Integer,RANDOMINTEGER As Integer Dim SINGLECHAR As String *1,filen2 As Integer'取單字節(jié) If MA<0 Them MA=MA*(-1) End If X=Rnd(-MA)'參數(shù)為負(fù) FILENUM=FreeFile Open FILENAME$ For Binary As #FILENUM '二進(jìn)制方式打開源文件 filen2=FreeFile Open FILE2$ For Output As #filen2’以順序文件打開目標(biāo)文件 For i=1 To LOF(FILENUM)'LOF()文件字節(jié)長 Get #FILENUM,i,SINGLECHAR'取單字節(jié)內(nèi)容 CHARNUM=Asc(SINGLECHAR) RANDOMINTEGER=Int(256*Rnd)'得到字母表 CHARNUM=CHARNUM Xor RANDOMINTEGER'異或 Print #filen2,Chr$(CHARNUM);’寫入目標(biāo)文件 Next I Close FILENUM Close filen2 ok ’調(diào)用成功對話框 End Sub 調(diào)用格式:ENDECODE 源文件名,密碼,目標(biāo)文件名 上面過程可以對任何EXE、COM、文本等文件進(jìn)行加解密(奇數(shù)次加密,偶數(shù)次解密),重演性極好,保密性特優(yōu),若對上述過程進(jìn)一步加工,如進(jìn)行多重隨機(jī)等手段處理,那么將會更上一層樓,在此不累述。 順便提一下,上面過程若對目標(biāo)文件同樣以二進(jìn)制文件打開、寫入,那么只能對純西文文本進(jìn)行加解密,對于純中文文本則通過修改取雙字節(jié)、I的步長為2來實(shí)現(xiàn),其它(中西文結(jié)合文本、EXE、COM等文件)則將得不到預(yù)期結(jié)果,其原因可以能是ASCII大于127的字符,不能正常顯示,不能用put語句正常寫入文件(得到的只是空格),有興趣者不妨一試。 |
利用 lstrlen 計(jì)算中英文混合字串的長度 |
在 32-bit 版本的 VB 底下, 將每一個(gè)字符都視為兩個(gè) Byte, 所以 Len("中英Mixed") 等于 7 LenB("中英Mixed") 等于 14 但是在很多場合底下, 我們希望中文字長度以 2 計(jì)算, 英文字母長度以 1 計(jì)算, 此時(shí)使用的方法如下: ' 欲計(jì)算字串 S 的長度 N = 0 For I = 1 To Len(S) C = Asc(Mid(S, I, 1)) ' 取得第 I 個(gè)字符組的字符碼 If C >= 0 And C <128 Then ' 英文 N = N + 1 Else ' 中文 N = N + 2 End If Next 看起來程序有點(diǎn)羅唆, 如果您不喜歡這個(gè)方法, 可以使用 Windows API 的 lstrlen 函數(shù), 假設(shè)假計(jì)算 S 的長度, 則 API 聲明式如下: Private Declare Function lstrlen Lib "kernel32" Alias "lstrlenA" (ByVal lpString As String) As Long 而調(diào)用的敘述則是: n = lstrlen("中英Mixed" + Chr(0)) Print n ' n 將等于 9 請注意調(diào)用 lstrlen 時(shí)必須加上 Chr(0), 因?yàn)榇艘缓瘮?shù)是根據(jù) Chr(0) 來判斷字串的結(jié)束。 調(diào)用 lstrlen 除了程序比較簡短之外, 速度也比我們寫 VB 程序判斷中英文字然后計(jì)算長度來的快。 |
利用 StrConv 計(jì)算中英文混合字串的長度 |
上一周說明利用 Windows API 的 lstrlen 計(jì)算中英文混合字串的長度之后,臺中的 Rose 讀者來函, 說還有更簡單的計(jì)算方法, 如下: LenB(StrConv("中英Mixed", vbFromUnicode)) 說真的, 因?yàn)楣P者懂得調(diào)用 Windows API, 所以竟然忽略了此一 VB 內(nèi)建的函數(shù),可見聞道有先后, 在此筆者亦希望先聞道的讀者能夠?qū)⒛男牡冒l(fā)表出來, 與喜歡 VB 的讀者交流。 StrConv 的作用是字串內(nèi)容的轉(zhuǎn)換, 其中將叁數(shù)二設(shè)定成 vbFromUnicode,作用是把「雙位元」的字串轉(zhuǎn)換成中文字占用 2 Bytes、英文占用 1 Bytes 的字串,所以緊接著調(diào)用 LenB, 便可以計(jì)算出中英文混合字串的長度。 |
如何傳遞不固定個(gè)數(shù)的叁數(shù)? |
定義副程序時(shí), 我們必須把叁數(shù)一一列出來, 例如: Sub MySub( P1, P2, ┅) 但如果我們將來調(diào)用副程序時(shí), 可能會傳入不固定個(gè)數(shù)的叁數(shù), 那么副程序該如何定義呢?答案如下: Sub MySub( ParamArray P() ) ' 把叁數(shù) P 定義成一個(gè)陣列 如此定義副程序之后, 以下都是將來可能出現(xiàn)的調(diào)用敘述: MySub "ABC" ' 只傳遞一個(gè)叁數(shù) MySub 1, 3, 9, 988, 776, 234 ' 傳遞 6 個(gè)整數(shù)叁數(shù) MySub 123, "abc", Date() ' 傳遞 3 個(gè)不同型別的叁數(shù) 以最后一個(gè)調(diào)用敘述為例, P(0) 叁數(shù)將等于 123, P(1) 叁數(shù)等于 "abc", P(2) 叁數(shù)則等于 Date() 函數(shù)的傳回值, 而由于 P() 是一個(gè)陣列, 我們可以利用以下方法讀取每一個(gè)叁數(shù): For i = 0 To UBound(P) ' P(i) 等于第 i 個(gè)叁數(shù) Next 最后, 請注意以 ParamArray 所定義的叁數(shù)一定是 Variant(不定型) 型別, 若要判斷每一個(gè)個(gè)別叁數(shù)的資料型別, 可以使用 TypeName 函數(shù)。 |