用VB進(jìn)行文本文件的再處理
越來越多的人開始認(rèn)識(shí)到Internet這一信息資源的巨大寶庫,但是把信息從網(wǎng)上下載下來后,繁雜多樣的文件格式卻給整理、使用帶來相當(dāng)大的麻煩。有的由于系統(tǒng)平臺(tái)的變化,甚至顯示出來是一團(tuán)亂糟糟東西。那么要想更好、更方便地利用網(wǎng)絡(luò)資源,一個(gè)得力的文本文件處理工具就顯得非常必要。如果四處去尋找一個(gè)這樣的工具,不僅不容易,找到后可能并不符合我們的要求,但是如果你有VB,那么為什么不自己開發(fā)一個(gè)這樣的工具程序呢?相信我,這并不困難,只要你已經(jīng)對(duì)VB有所了解,一個(gè)方便實(shí)用的小工具已經(jīng)在等著你了!
先來分析一下這個(gè)程序要完成的主要任務(wù)吧,象這樣的文本處理,可以歸納為兩種形式,就是替換和清除,如果把清除看成是替換成空的話,那么唯一個(gè)任務(wù)就是替換了。就替換面言,可能會(huì)有以下幾種形式:
1、將一段文字替換成另一段
2、將某兩個(gè)特殊標(biāo)識(shí)符之間的文字替換成另外一些文字
3、將某兩個(gè)特殊標(biāo)識(shí)符之間的文字按照某種規(guī)律進(jìn)行轉(zhuǎn)換
搞清這幾個(gè)任務(wù),我們就可以著手編程了。一個(gè)好的程序員,不應(yīng)每次都是從零做起,平常一些基礎(chǔ)模塊的積累,可以增加我們制作大程序的信心。下面我先對(duì)程序中用到的我的基礎(chǔ)庫中的內(nèi)容進(jìn)行一下介紹,然后再解決每一個(gè)具體問題。
一、準(zhǔn)備過程
1、字符串處理函數(shù)(StrHead)
用VB來實(shí)現(xiàn)這個(gè)程序,首先要解決的是如何方便地進(jìn)行字符串處理,VB中原有的函數(shù)InStr和Mid,使用起來并不方便,我利用這兩個(gè)函數(shù)編寫出一個(gè)新的函數(shù):StrHead,該函數(shù)根據(jù)指定的斷點(diǎn)字符將字符串截?cái)?,斷點(diǎn)前的字符串被返回,后面部分保留在原字符串中,該函數(shù)可以完成大部分字符串操作。函數(shù)代碼如下:
Public Function StrHead(ss As String,
ByVal c As String) As String
Dim i As Long
i = InStr(ss, c)
If i > 0 Then
StrHead = Mid(ss, 1, i - 1)
ss = Mid(ss, i + Len(c))
Else
StrHead = ss
ss = ""
End If
End Function
2、文本文件類(TextFile)
程序中涉及到很多文件操作,為了方便,可以先將對(duì)文件操作的過程封裝到一個(gè)類中,這樣不僅可以提高編程效率,還可以大大減少出錯(cuò)的機(jī)會(huì)。因?yàn)楸菊n題主要是面對(duì)文本文件的,這樣我們只編寫一個(gè)處理文本文件讀寫類(TextFile)就可以了,該類的幾個(gè)主要功能函數(shù)列在下面:
' 文本文件類(TextFile.cls)
Option Explicit
Dim FileNum As Integer
' 打開文件用于寫
Public Function OpenWrit(fn As String) As Boolean
On Error GoTo OWErr
FileNum = FreeFile
Open fn For Output Access Write As #FileNum
OpenWrit = True
Exit Function
OWErr:
OpenWrit = False
End Function
' 打開文件用于讀
Public Function OpenRead(fn As String) As Boolean
On Error GoTo ORErr
FileNum = FreeFile
Open fn For Input Access Read As #FileNum
OpenRead = True
Exit Function
ORErr:
OpenRead = False
End Function
' 關(guān)閉文件
Public Sub CloseFile()
If FileNum > 0 Then
Close #FileNum
FileNum = 0
End If
End Sub
' 從文件中讀取一行
Public Function GetLine(S As String) As Boolean
On Error GoTo NotGet
If EOF(FileNum) Then GoTo NotGet
Line Input #FileNum, S
GetLine = True
Exit Function
NotGet:
GetLine = False
End Function
' 往文件中寫入一行
Public Function PutLine(Byval S As String) As Boolean
On Error GoTo NotPut
Print #FileNum, S
PutLine = True
Exit Function
NotPut:
PutLine = False
End Function
' 類在結(jié)束時(shí),自動(dòng)關(guān)閉文件
Private Sub Class_Terminate()
CloseFile
End Sub
二、替換單元類
做為一個(gè)通用的工具,我們現(xiàn)在并不知道要將什么替換為什么,這些信息是要在使用者使用時(shí)告訴程序的,這就需要將各種替換任務(wù)進(jìn)行參數(shù)化,用最簡單明確的方式描述出來。這里我們實(shí)現(xiàn)的個(gè)替換單元類(reUnit),用它來接受參數(shù)并完成替換任務(wù)。
1、替換條件的描述及初始化
為了能在一次處理中,實(shí)現(xiàn)多種替換,定義一個(gè)“替換單元”類:reUnit,來承擔(dān)主要的替換任務(wù)。這個(gè)類中定義了替換的條件:
Dim headChr As String '啟始符
Dim tailChr As String '結(jié)束符
Dim reStr As String '替換為
Dim mapObj as Object '映射對(duì)象
通過上面三個(gè)變量來描述替換條件:headChr和tailChr代表檢索的起點(diǎn)和終點(diǎn),當(dāng)tailChr為零長時(shí),表示只對(duì)某字符串進(jìn)行替換。reStr是替換后的字符串,為零長時(shí)即表示清除。該類用下面兩個(gè)函數(shù)來設(shè)置上面的三個(gè)變量:
Public Sub Init(ByVal S As String)
headChr = EscStr(StrHead(S, ","))
tailChr = EscStr(StrHead(S, ","))
reStr = EscStr(S)
If Left(reStr,1)="@" Then
'第一個(gè)字符是"@",它所代表的是一個(gè)映射類
Set mapObj = CreateObject(Mid(reStr,2))
End If
End Sub
Private Function EscStr(ByVal S As String) As String
Dim h As Long
EscStr = ""
Do While Len(S) > 0
EscStr = EscStr & StrHead(S, "&")
If Len(S) > 0 Then
h = "&H" & StrHead(S, ";")
EscStr = EscStr & Chr(h)
End If
End Function
函數(shù)Init接受一個(gè)字符串S,其中應(yīng)包含“起點(diǎn)”、“終點(diǎn)”和替換后的字符串,他們之間用逗號(hào)分隔。為了能將非鍵盤字符加入其中,可以用“&HHHH;”的形式將任意字符插入其間,HHHH表示一個(gè)十六進(jìn)制數(shù),通過EscStr函數(shù)來完成這種替代。
這里需要說明的是,類中定義了一個(gè)mapObj變量,它是為了實(shí)現(xiàn)“特殊標(biāo)識(shí)符之間的文字按照某種規(guī)律進(jìn)行轉(zhuǎn)換”而設(shè)計(jì)的。因?yàn)檫@種規(guī)律性現(xiàn)在我們并不知道,我們只能在這里為今后留下的一個(gè)接口,假設(shè)一個(gè)類實(shí)現(xiàn)了某種規(guī)律的映射,并通過下面這樣的函數(shù)來提供這種映射:
Public Function Map(Byval ss as String) as String
我們規(guī)定,如果reStr的第一個(gè)字符是"@"的話,它所代表的就不是一直接替換為的字符串,而是的個(gè)映射類的標(biāo)識(shí)名,我們將通過CreateObject函數(shù)來建立這個(gè)對(duì)象,在替換時(shí)調(diào)用它的Map函數(shù)。
2、替換函數(shù)
該類的Replice函數(shù)完成對(duì)字符串的替換任務(wù),由于是對(duì)文件中的數(shù)據(jù)以一行為單位依次調(diào)用該函數(shù)的,所以要考慮到“起點(diǎn)”與“終點(diǎn)”不在同一行上的情況,所以首先定義一個(gè)標(biāo)記變量:
Dim flag As Boolean
當(dāng)flag為假時(shí),表示不處在檢索“終點(diǎn)”狀態(tài),為真時(shí)為檢索“終點(diǎn)”狀態(tài)。下面是Replice函數(shù)的代碼:
Public Function Replice(ByVal S As String) As String
Dim tempS as String
If Len(tailChr) > 0 Then ' 檢索成對(duì)標(biāo)記
Do While Len(S) > 0
If Not flag Then ' 不處在檢索“終點(diǎn)”狀態(tài)
If InStr(S, headChr) > 0 Then
Replice = Replice & StrHead(S, headChr)
flag = True
Else ' 處在檢索“終點(diǎn)”狀態(tài)
Replice = Replice & S
Exit Do
End If
End If
If InStr(S, tailChr) > 0 Then ' 檢索“終點(diǎn)”
tempS=StrHead(S, tailChr)
If mapObj Is Nothing Then
Replice = Replice & reStr
Else
' 如果存在映射類的話,調(diào)用映射類的Map函數(shù)
Replice = Replice & mapObj.Map(tempS)
End If
flag = False
Else
Exit Do
End If
Else ' 檢索單字符串
Do While Len(S) > 0
If InStr(S, headChr) > 0 Then
Replice = Replice & StrHead(S, headChr)
Replice = Replice & reStr
Else
Replice = Replice & S
Exit Do
End If
End If
End Function
三、完成文件替換
有了上面的基礎(chǔ)后,就可以通過一個(gè)全局模塊將具體到文件的的功能實(shí)現(xiàn)了:
1、替換單元集合
定義一個(gè)集合來保存各個(gè)替換單元,我們?cè)O(shè)想將替換條件保存于一個(gè)文件中,稱之為“條件定義文件”,文件中每一行定義一個(gè)替換條件,定義格式如上文對(duì)替換單元類中對(duì)Init參數(shù)的描述。這樣可以很方便在實(shí)現(xiàn)單元集合的初始化:
Public reUnits As Collection
' 全局的替換單元集合
Public Function InitUnits(ByVal fn As String) As Boolean
Dim F As New TextFile, S As String
Dim unit As reUnit
If F.OpenRead(fn) Then
Set reUnits = New Collection
Do While F.GetLine(S)
If Len(S) > 0 Then
Set unit = New reUnit
unit.Init S
reUnits.Add unit
End If
InitUnits = True
Else
InitUnits = False
End If
End Function
2、單個(gè)文件替換
當(dāng)確定了所要替換的文件及替換后的文件,就可以分別調(diào)用替換單元集合中的單元替換函數(shù)來進(jìn)行替換了:
Public Function ReplaceFile(ByVal sFn As String,ByVal dFn As String) As Boolean
Dim sFile As New TextFile, dFile As New TextFile
If Not sFile.OpenRead(sFn) Then GoTo reErr
If Not dFile.OpenWrit(dFn) Then GoTo reErr
Dim unit As reUnit
Dim buff As String
Do While sFile.GetLine(buff)
For Each unit In reUnits
'調(diào)用集合中的每一個(gè)單元進(jìn)行替換
buff = unit.Replice(buff)
Next
If Len(buff) > 0 Then dFile.PutLine buff
ReplaceFile = True
Exit Function
reErr:
ReplaceFile = False
End Function
3、替換過程
利用前兩個(gè)函數(shù),實(shí)現(xiàn)文件替換的全過程,該過程需要“源文件”、“目標(biāo)文件”及“條件定義文件”三個(gè)參數(shù),也是整個(gè)程序所需的參數(shù):
Public Sub RepFile(ByVal sFn As String, ByVal dFn As String, ByVal defFn As String)
Dim info As String
If InitUnits(defFn) Then
If ReplaceFile(sFn, dFn) Then
info = "替換成功!"
Else
info = "文件不能打開!"
End If
Else
info = "定義文件不能打開!"
End If
MsgBox info
End Sub
四、界面及完成整個(gè)程序
1、界面窗口
窗體(frmRep)可以讓使用者輸入上面要求的三個(gè)參數(shù),然后調(diào)用RepFile實(shí)現(xiàn)替換。在這個(gè)窗體中,主要由三個(gè)文本編輯框(txtFn(0-2))和兩個(gè)按鈕(cmOk、cmClose)組成,兩個(gè)事件響應(yīng)函數(shù)如下:
Private Sub cmOk_Click()
RepFile txtFn(0), txtFn(1), txtFn(2)
End Sub
Private Sub cmClose_Click()
Unload Me
End Sub
2、入口函數(shù)
可以把frmRep窗體定義為啟動(dòng)窗體,但這樣使程序在應(yīng)用過程中缺少靈活性,所以不妨定義一個(gè)入口函數(shù),對(duì)命令行參數(shù)進(jìn)行分析,當(dāng)條件滿足時(shí),就可以不必激活frmRep窗體了:
Public Sub
Dim cm As String
Dim sFn As String, dFn As String, defFn As String
cm = Command
If Len(cm) > 0 Then sFn = StrHead(cm, " ")
If Len(cm) > 0 Then dFn = StrHead(cm, " ")
If Len(cm) > 0 Then defFn = StrHead(cm, " ")
If Len(sFn) > 0 And Len(dFn) > 0 And Len(defFn) > 0 Then
RepFile sFn, dFn, defFn '條件滿足,進(jìn)行替換
Else
Dim frm As New frmRep '條件不足,建立窗體
frm.txtFn(0) = sFn '把已有條件預(yù)先填上
frm.txtFn(1) = dFn
frm.txtFn(2) = defFn
frm.Show
End If
End Sub
聯(lián)系客服