◆吳 爭(zhēng) 劉 璐/谷城縣審計(jì)局
由于原始數(shù)據(jù)錄入不規(guī)范,經(jīng)常會(huì)造成數(shù)據(jù)分析人員在前期數(shù)據(jù)結(jié)構(gòu)化整理工作上花費(fèi)較長(zhǎng)的時(shí)間和較多的精力。近日,筆者在某審計(jì)項(xiàng)目中遇到此類情況,較多基礎(chǔ)數(shù)據(jù)全部錄入在一個(gè)單元格內(nèi),且沒有較明顯的規(guī)則來提取,因?yàn)樾枰矸葑C號(hào)碼和手機(jī)號(hào)碼等關(guān)鍵字段,所以必須要對(duì)基礎(chǔ)數(shù)據(jù)開展清洗工作,轉(zhuǎn)換成標(biāo)準(zhǔn)格式以滿足審計(jì)需要。
部分?jǐn)?shù)據(jù)(以下所有截屏數(shù)據(jù)均為演示數(shù)據(jù))如圖1所示。
圖1
從圖中可以看到,C列單元格中包含了人員的社區(qū)信息、身份證號(hào)碼、性別、手機(jī)號(hào)碼、戶籍屬性。
起初考慮用VLOOKUP函數(shù)加入數(shù)組計(jì)算方式來解決,設(shè)置要輸出身份證號(hào)碼的單元格D2=VLOOKUP(0,MID(C2,ROW($1:$99),18)*{0,1},2,0)。思路是 MID 函數(shù)依次從C2的第1、2、3、4……直至99個(gè)位置,提取長(zhǎng)度為18位的字符,然后分別乘以0和1,即常量數(shù)組{0,1}。如果MID函數(shù)的結(jié)果為文本,那么乘以{0,1}后結(jié)果為錯(cuò)誤值{#VALUE!,#VALUE!};如果MID函數(shù)的結(jié)果為數(shù)值,結(jié)果即為所需提取的18位身份證號(hào)碼。
實(shí)際運(yùn)算后發(fā)現(xiàn)函數(shù)提取超過11位顯示為科學(xué)計(jì)數(shù),如圖2所示。
圖2
于是考慮用英文引號(hào)拼接函數(shù)來調(diào)整顯示格式,修改單 元 格 D2="'"&VLOOKUP(0,MID(C3,ROW($1:$99),18)*{0,1},2,0),運(yùn)行結(jié)果如圖3。
圖3
觀察發(fā)現(xiàn),計(jì)算結(jié)果與實(shí)際不符??磥砝肰LOOK?UP函數(shù)加入數(shù)組計(jì)算提取18位的身份證號(hào)碼行不通,只能另辟蹊徑。
VBA正則表達(dá)式是一種特殊的字符串模式,用于匹配字符串排列的一套規(guī)則。我們可以用這個(gè)規(guī)則去匹配查找可以匹配上的字符串(即單元格中任意想要的信息)。簡(jiǎn)單來說,就是單元格中存在一個(gè)文本信息,這個(gè)信息中有一些我們需要的內(nèi)容,也有很多不需要的內(nèi)容,通過正則表達(dá)式幫助我們從文本中提取想要的內(nèi)容。
如上例中因?yàn)樯矸葑C號(hào)碼出現(xiàn)位置不固定,我們無法使用函數(shù)LEFT或者M(jìn)ID或者RIGHT來獲取身份證號(hào)碼,使用正則表達(dá)式可以快速獲取身份證號(hào)碼。
在表格中按下Alt+F11進(jìn)入設(shè)計(jì)模式,插入模塊,編寫語(yǔ)句后保存。語(yǔ)句及注釋如下:
Function GetCardID(rng As Range,i As Integer)'格式=GetCardID(A1,1),A1代表單元格,1代表從里面提取第幾組,必須在字符之間,但加"|$"可以在字符之后
Dim Reg
Dim Mhs
Set Reg=CreateObject("vbscript.regexp")'創(chuàng)建正則表達(dá)式對(duì)象
With Reg
.Pattern="(?:^|D)(d{18}|d{15})(?=^|D)"'匹配正則表達(dá)式,加"|$"可以提取在字符串之后
Dim Reg
.Global=True
Set Mhs=Reg.Execute(rng.Value)'將所有匹配的字符串賦值給Mhs
End With
If i-1<0 Or i>Mhs.Count Then'如果自定義函數(shù)的第二參數(shù)小于0或者大于匹配字符串組數(shù)就繼續(xù)執(zhí)行
GetCardID="#VALUE"'結(jié)果顯示"#VALUE"錯(cuò)誤值
Exit Function'退出過程
End If
GetCardID=Mhs(i-1).submatches(0)'結(jié)果等于匹配字符串的指定組數(shù)
End Function
其中With語(yǔ)句塊作用是匹配15位或18位的字符串賦值給Mhs,IF語(yǔ)句塊作用是判斷自定義函數(shù)的第二參數(shù)是否在計(jì)算范圍,兩個(gè)語(yǔ)句塊之后就是從0開始進(jìn)行匹配計(jì)算,成功匹配的字符串賦值給GetCardID函數(shù)。
設(shè)置要輸出身份證號(hào)碼的單元格D2=GetCardID(C2,1),往下填充至需要計(jì)算的行,得到所需準(zhǔn)確結(jié)果,如圖4所示。
圖4
同樣的思路編寫提取手機(jī)號(hào)碼的語(yǔ)句:
Function GetPhoneNumber(rng As Range,i As Integer)
Dim Reg
Dim Mhs
Set Reg=CreateObject("vbscript.regexp")
With Reg
.Pattern="(?:^|D)(d{11})(?=D|$)"
.Global=True
Set Mhs=Reg.Execute(rng.Value)
End With
If i-1<0 Or i>Mhs.Count Then
GetPhoneNumber="#VALUE"
Exit Function
End If
GetPhoneNumber=Mhs(i-1).submatches(0)
End Function
設(shè)置要輸出手機(jī)號(hào)碼的單元格E2=GetPhoneNumber(C2,1),往下填充至需要計(jì)算的行,得到所需準(zhǔn)確結(jié)果,如圖5所示。
圖5
至此,利用VBA正則表達(dá)式快速檢索匹配字符串的功能,從混合內(nèi)容且無規(guī)則的數(shù)據(jù)中檢索提取所需數(shù)值(字符串)完美實(shí)現(xiàn),既提高了工作效率,又保證了工作精度。