有一位美國佬編寫的<<精通正則表達式>>專業(yè)書籍是世人公認的正則權(quán)威著作.但它不太適合初學者,尤其是沒有相關編程語言背景及書中所及的種種計算機技術(shù)知識的讀者.其中很多晦澀難懂的內(nèi)容在VBA中用不上或者對你來說根本無用的,而初學者的你卻根本不知道怎樣取舍.事實上,本人還沒有發(fā)現(xiàn)一本針對VBA平臺的正則專業(yè)書籍.網(wǎng)絡可見到少量VBA正則教程,但內(nèi)容多是”點到為止”.
鑒于此,有此貼文.在這里感謝本論壇liucqa老師的鼓勵,在之前本人寫過一篇正則對象操作的短文,liucqa老師留貼建議多寫一點,但一致未能成文.此帖算是對liucqa老師的交代.
內(nèi)容提要
目錄
第一篇 基礎篇
一、 正則表達式概論—理解正則表達式
二、 正則表達式與VBA的交互—正則表達式的實現(xiàn)
三、 正則元字符—字符的表示法
四、 正則元字符—數(shù)量的表示法
五、 正則元字符—位置的表示法
六、 正則元字符—分組及控制表示法
第二篇 進階篇
一、 元字符與字符集
二、 ^$的位置到底是哪里
三、 字符組內(nèi)部元字符轉(zhuǎn)義規(guī)則
四、 字符組與多選結(jié)構(gòu)“|”
五、 否定環(huán)視與否定字符組
六、 順序環(huán)視的多角度理解與應用
第三篇 原理篇
一、匹配的基本術(shù)語
二、匹配總原則
三、正則表達式匹配的基本過程
四、回溯
五、回溯的總結(jié)
六、回溯與效率
七、災難回溯
第四篇 技巧篇
一、匹配具有多種形態(tài)結(jié)構(gòu)的字符串
二、匹配特定位置上的字符串
三、匹配其內(nèi)部由相似結(jié)構(gòu)字符串構(gòu)成的字符串
四、在一大段文本中,匹配一對特定字符串之間的字符串
五、匹配一對特殊字符界定的之間的字符串,但其內(nèi)部包含兩端的界定字符
第一篇 基礎篇
一、正則表達式概論----理解正則表達式
文本處理是一項常見的工作任務,比如:在一段文本或數(shù)據(jù)中,查找、替換、提取、驗證、分離和刪除等特定字符或字符串。在幾乎所有文本編輯器中(如word/excel/VBE等)都提供了字符串的查找/替換功能;在編程語言的世界里更是提供了豐富的字符處理函數(shù)和方法。VBA中有Find(查找某字符串)、Replace(用一字符串去替換文本中的另一字符串)、LIke(判斷某字符串是否存在)等等。
編程語言本身提供的字符處理函數(shù)或方法,具有用法簡單、處理快速和使用便捷的特點。不過這些函數(shù)或方法也存在很大缺陷:它們通常都是對非常具體的字面文字進行操作,假如要處理某一類具有某些相似特征的字符或字符串,就顯得力不從心了。舉個例子,要求在一大段文本中,查找所有的符合規(guī)范的電子郵箱。如果用VBA本身提供的字符處理函數(shù)來處理,顯然不是一件容易的事??梢?,在現(xiàn)實的世界里對復雜動態(tài)文本的處理,僅靠編程語言本身是不夠的。為此,人們找到了一種功能更為強大的文本處理解決方案----正則表達式方案。
正則表達式是強大、便捷、高效的文本處理工具。利用它使用者可以描述和分析任何復雜的文本,配合編程語言或文本編輯器提供的支持,正則表達式能夠查找、替換、提取、驗證、添加、刪除、分離和修整各種類型的文本和數(shù)據(jù)。當今主流編程語言(如:java/C#/C++/.net/php/pcre/perl等)幾乎都提供了對正則表達式的支持;有些文本編輯器(如Dreamweaver)在編輯查找框中也可直接輸入正則表達式,實現(xiàn)不限于字面文字的搜索與替換.VBA雖然只是對正則提供簡單支持,但是它也可以完成一些用VBA函數(shù)或方法難以處理的文本處理任務。
(一)正則表達式方案處理文本的基本思路
1、顯然,無論進行何種文本處理操作,首先要在目標文本中找出指定的字符串,而要查找它們必須得描述出該字符串的特征。比如,你要驗證用戶輸入的是否是一個正確的電子郵箱,肯定不可能去枚舉世界上所有存在的電子郵箱,因而首先得依據(jù)電子郵箱規(guī)范,建立一個電子郵箱的模式,然后比照該模式到文本中去查找驗證,從而判斷目標文本中是否存在與模式相吻合的字符串(這個過程也稱之匹配過程,查找到的結(jié)果叫”匹配”)。一個簡單的電子郵箱模式可以表示為:
^\S+@\S+$
這個代碼模式就是電子郵箱的正則表達式,所以正則表達式是一種可以在許多現(xiàn)代應用程序和編程語言中使用的特殊形式的代碼模式。編制這樣的代碼模式,也就是編制正確高效的正則表達式,是我們學習和研究正則表達式的主要任務。
2、如何將編制好的正則表達式應用于編程語言,實現(xiàn)我們真正的需要,這是學習和使用正則的第二個問題,在這一點上,不同的編程語言其實現(xiàn)方式是不一樣的.慶幸的是,較之編制正則表達式,掌握它們是非常簡單的事。我們會在本篇的第二章“正則與VBA的交互”中詳細論述。
(二)正則表達式的基本組成單元—元字符(序列)
從電子郵箱的正則表達式(^\S+@\S+$)可以看到,正則表達式是由一些”特殊字符”組成的。人們常常把這些組成正則表達式的”特殊字符”稱之為元字符。元字符是正則表達式事先規(guī)定或約定的,用來表示字符、位置、數(shù)量和控制的專用符號。在組成正則表達式的元素中,有的是由兩個或多個特殊字符組成一個單元,表示單一意義。如上面電子郵箱正則中,”\S”表示一個非不可見字符,我們可以稱之為元字符序列.在正則表達式中也可以有字面字符,如郵箱正則的字符“@”,在這時表示的是字面上”@”.所以從形式上觀察,正則表達式是由元字符、元字符序列或字面字符組成的,用于描述字符或字符串特征的一個代碼模式.正則表達式也可以僅由字面字符組成,如”正則ABC”.
你是否有一種似曾相識的感覺?對!這不是什么新鮮的想法.遠古的DOS時代,前輩門就曾用*號代表任意多個字符,用?號代表一個任意字符,那時稱之為“通配符”;當下的VBA中Like函數(shù)的參數(shù)里有更多的特殊字符或結(jié)構(gòu),用來描述字符或字符串模式.不過,正則表達式里,那些”特殊字符”更多,語法規(guī)則更豐富,可以認為,它相當于是一門”微型”語言.
接下來,本章會把所有的”元字符(序列)”分類展示給你,不是要你立馬記住或掌握它,目的是讓你有個概貌,避免在以后的學習中迷失方向.
1.正則表達式規(guī)定了多種方法或符號用來表示世界各國使用的文字字符。如:
下面列舉了VBA中正則表示字符的所有元字符(序列),在以后的章節(jié)中會詳細介紹.
(1) 常用不可打印字符:\n、\t、\f、\r、\v
(2) 八進制轉(zhuǎn)義:\num (num是一個八進制數(shù))
(3) 十六進制轉(zhuǎn)義:\xnum (num是一個十六進制數(shù))
(4) Unicode轉(zhuǎn)義:\unum (num是unicode代碼點)
(5) 控制字符:\cchar (char是A-Z之間的任意字母)
(6) 普通字符組:[a-z]和[^a-z]
(7) 幾乎能匹配任何字符的元字符:英文句點
(8) 字符組縮略表示法:\w、\d、\s、\W、\D、\S
2.表示字符或字符串數(shù)量(連續(xù)出現(xiàn)的次數(shù))的元字符:*、?、+、{n}、{n,m} 例:
3.表示位置的元字符(序列):^、$、\b、\B、(?=…)、(?!...)例:
4.在正則表達式中起分組、捕獲和控制作用的元字符(序列):
(…)、(?:…)、\1、…|…|…、*?、+?、??、{num,num}?
例:
捕獲9.PNG (22.65 KB, 下載次數(shù): 921)
捕獲.PNG (22.47 KB, 下載次數(shù): 834)
(三)用正則處理文本的一個例子
我們已經(jīng)認識了幾個簡單的元字符(序列),并能用它們構(gòu)建一些實用的正則表達式,那么,怎樣把它們應用于VBA中呢?,下面我們用正則在VBA中來完成一個簡單的任務:
目標文本:”正則表達式其實很簡單 “
任務:刪除目標文本中行尾空格.
分析:
1.\s可表示空格,+表示出現(xiàn)一個或多個字符,所以可用”\s+”表示連續(xù)多個空格.$表示一行的行尾,于是可用以下正則表達式描述行尾的若干空格:
\s+$
2.我們把上面的正則代碼表達式作用于目標文本,查找與模式吻合的字符(串),并用空字符替換,從而達成實現(xiàn)刪除空格任務。
下面是完整的VBA代碼:
Sub Test()
Dim regx, S$, Strnew$
S = "正則表達式其實很簡單 "
Set regx = CreateObject("vbscript.regexp")
regx.Pattern = "\s+$"
regx.Global = True
Strnew = regx.Replace(S, "")
MsgBox Strnew
End Sub
這個簡單的例子說明了正則實現(xiàn)的一般步驟:
1、 創(chuàng)建變量:這個例子中,變量regx是一個對象,S是字符串變量;Strnew也是字符串變量.
2、 把目標文本賦值給變量S
3、 創(chuàng)建一個正則對象regx
4、 設置正則對象regx的pattern屬性,即把正則表達式以字符串形式賦值給pattern.
5、 設置正則regx對象的其它屬性,例子中設置Global屬性為真
6、 應用對象提供的方法,實現(xiàn)相應功能.例子中,利用regx對象的Replace方法實現(xiàn)替換.
7、 輸出處理后的字符串.
到這里,你已經(jīng)完全了解了用正則處理文本的基本過程和思路,以及在VBA中使用正則的代碼框架.以后的任務是全面掌握正則的所有元字符和它們的工作原理,另外還需要進一步了解正則對象的各種屬性和方法.
要提醒的是,”基礎篇”的應用實例或許并不是解決該任務的最佳方案,也或許是一些看似很無聊的例子,但請不要忽視它們.正是透過這些簡單的實例,揭示了概念的本質(zhì).
補充內(nèi)容 (2014-6-20 19:04):
最近看了liucqa老師一個貼子,在處理"大字符串"時,即使可用VBA函數(shù)或方法處理,但不如用正則處理速度快.比如:用Split將用逗號連接的10萬個數(shù)字字符串轉(zhuǎn)化的為數(shù)組,如果用正則處理,只需要一半的時間.
補充內(nèi)容 (2016-6-8 07:30):
本頁例中的regx.Global=True語句,此時不是必須的,只是為了說明屬性的應用.
二.正則與VBA的交互—正則表達式的實現(xiàn)
在繼續(xù)學習正則元字符特性或編制自己的正則表達式時,常常需要對其測試.你可以用一些專門的正則測試工具(推薦RegxBuddy);也可以自己編制VBA代碼進行測試。不過建議初學者,經(jīng)常編寫VBA代碼進行測試,這樣可以提高今后實際應用正則的能力。所以,在進一步學習正則元字符特性之前,我們先介紹正則與VBA的交互的相關知識。你可以快速閱讀或越過本章內(nèi)容,在以后具體應用時,再經(jīng)常回頭查閱。當然也可以用上一章學到的知識詳細研究本章內(nèi)容,在以后的學習中專注于正則表達式本身.
用正則處理文本,是通過正則表達式與程序設計語言的交互來實現(xiàn)的。其交互方式在不同編程語言中分為三大類:
一是集成式。Perl語言本身內(nèi)建正則操作符,可以直接作用于正則表達式.操作符作用于正則表達式就像數(shù)學的+-號作用于數(shù)字一樣.不需要構(gòu)建正則對象。例如:任務是要把變量$text保存的文本中的空行替換為標簽(<P>)。
正則表達式
^$ 表示空行.
在Perl語言中,可以用一句代碼實現(xiàn)替換:$text=~ s/^$/<p>/g
二是函數(shù)式處理。Java等語言,為正則處理提供了一些便捷函數(shù),以節(jié)省工作量.用戶不需要首先創(chuàng)建一個正則對象,而是用靜態(tài)函數(shù)提的臨時對象來完成正則處理,處理完后把臨時對象拋棄. 正則表達式對于函數(shù)相當于一個參數(shù), 這種方式的優(yōu)點是”隨手”可用,但不適宜在對時間要求很高的循環(huán)中使用.所以java也提供了下面講到的面向?qū)ο蟮某绦蚴教幚?
三是面向?qū)ο蟮某绦蚴教幚?。這是大多數(shù)編程語言的正則處理方式。VBA平臺采用的也是這種方式。面向?qū)ο蟮某绦蚴教幚矸绞剑紫缺仨殑?chuàng)建一個正則對象的實例,然后設置對象必要的屬性,最后用對象的方法來完成指定的任務。(提示:不同編程語言的正則對象具有的屬性和方法,其項目多少或功能強弱有所不同,所以,在VBA中使用正則如果發(fā)現(xiàn)沒有某種其它語言的方法或?qū)傩?,請不要感到困?
在上一章中,我們給出了一個用VBA刪除行尾空格的正則處理例子,它代表了一般的代碼框架模式,下面再看一看它的結(jié)構(gòu)特點,并對每一部分的代碼段進行剖析:
Sub test()
Dim regx,S$,Strnew$ 1.定義變量代碼段
S=”正則表達式其實很簡單 “ 2.目標文本字串變量賦值代碼段
Set regx=createobject(“vbscript.regexp”) 3.創(chuàng)建正則對象代碼段
Regx.pattern=”\s+$” 4.設置正則對象的pattern屬性代碼段
Regx.global=true 5.設置正則對象的其它屬性代碼段
Strnew=regx.replace(s,””) 6.應用正則對象方法代碼段
Msgbox strnew 7.處理返回值代碼段
End sub
1.定義變量代碼段
不必講解了吧.
2.目標文本字符串賦值代碼段
目標文本,可能存在于文本文檔、Word文檔、HTML文檔或Excel文檔等文檔之中。正則對象并不能直接作用于這些文檔,只能作用于它們的副本。所以用VBA正則處理這些文檔,必須首先從這些文檔中讀出字符串并賦值于字符變量。如果任務是修改文本,那么,你可能需要編寫額外的代碼將修改后的文本字符串重新寫回原文檔中.
例:假如目標文本存在于當前表格A1單元格中.可使用下列代碼賦值于字符變量S
S=Activesheet.[a1]
目標文本也可能分別存在于一個數(shù)組中,那么,你可能需要通過循環(huán)逐一處理.
你也可以直接以輸入的方式,賦值給字符變量,就像上面的例子.這時特別注意的是:半角雙引號是VBA語言中的保留字符,如果目標文本中本身含有半角雙引號,則必須轉(zhuǎn)義,轉(zhuǎn)義方法是:用重復的雙引號表示一個雙引號.
例:目標文本為:”我們用”汗牛充棟”、”學富五車”形容一個人讀的書、擁有的知識多?!?
將之賦值給S的代碼為:
S=”我們用””汗牛充棟””、””學富五車””形容一個人讀的書、擁有的知識多?!?/p>
3.創(chuàng)建正則對象代碼段
文本處理的各種操作,都是通過操作正則對象來完成的.所以必須創(chuàng)建正則對象.VBA創(chuàng)建或聲明正則對象有兩方式:早期綁定和后期綁定,你可以根據(jù)自己喜好選擇其一:
早期綁定: (需要在VBE--工具--引用中勾選Microsoft VBScript Regular Expressions 5.5)
Dim regx AS RegExp
Set regx=new regexp (或dim regx as new regexp)
后期綁定:
Set regex = CreateObject("VBScript.RegExp")
利用上述兩種方式創(chuàng)建或聲明正則對象,實際上是調(diào)用Microsoft VBScript腳本的regexp正則對象。Microssoft VBScript腳本,包含在Internet Eeplorer 5.5以及之后的版本中.該腳本中的正則表達式執(zhí)行的是ECMA-262第3版所規(guī)定的標準,與JavaScript腳本中的正則執(zhí)行標準是相同的。1.0版只是為了向后兼容的目的,功能很弱。
(提示:在VBA中也可調(diào)用JavaScript(Jscript)或ruby等腳本中的正則對象,Jscript的元字符及特性與VBscript是一樣的,但它的方法或?qū)傩砸嘁稽c,或者說對正則的支持更強一些.ruby本人不懂,不太了解它的元字符集,只是看到論壇上有人使用)
4.設置對象的pattern屬性
語法:object.pattern=”正則表達式”
Object是一個正則對象.
把自己編制的正則表達式,以字符串的形式賦值給pattern屬性。注意要用英文雙引號將正則表達式包圍起來.
并且要在對象名與屬性名之間用英文點號隔開.屬性名pattern是保留字,固定不變的,對象名是用戶自定義的。
接下來的兩個步驟是對正則對象的操作,通過設置或使用正則對象的屬性和方法,以實現(xiàn)對文本的處理.正則對象的屬性和方法不多,列表于下:
5.設置對象的其它屬性
除Pattern屬性外,正則對象還有其它三個屬性,其屬性值有False和True,默認值都是False。如果要使用默認屬性,可以不用顯示設置;如果要改變默認屬性,則需要顯示設置:
Global 當屬性值為False時,只要在目標文本中,找到一個匹配時,即停止搜索。如果想要找出目標文本中的所有匹配,那么需要把它的屬性值設置為True。
IgnoreCase 設置對英文字母大小寫是否敏感。默認值False, 對大小寫敏感;設置為True,忽略大小寫.
MultiLine 它影響且只影響元字符^和$的意義。值為False,無論目標文本是多少行,整個文本中則只有一個開始位置,^表示第一行的開始;只有一個行結(jié)束位置,$表示文本末尾位置。值為True,那么,^和$分別表示每一行的行首和行尾位置。
下面來完成一個簡單的任務,再具體認識各屬性的使用方法:
有一兩行的文本:
Aaa
Bbb
任務要求:
1.在文本開始和結(jié)束處,分別插入一個”@”符號;
2.在文本每行的開始和行尾分別插入”@”符號。
正則表達式:
^|$ 表示匹配行開始或結(jié)束位置
任務1代碼:
Sub test1()
Dim reg, s$
s = "Aaa" & vbLf & "bbb" '這里用vblf 表示行之間的換行符
Set reg = CreateObject("vbscript.regexp")
reg.Pattern = "^|$"
reg.Global = True
s = reg.Replace(s, "@")
MsgBox s
End Sub
討論:
Msgbox 最后顯示的結(jié)果為:
@Aaa
Bbb@
代碼中修改了global的默認屬性值,設置為true;目的是保證能找到并替換全部的開始或結(jié)束位置。如果保持默認屬性,則只會在開始處插入一個@號。
正則對象Reg的其它兩個屬性保持為默認。因為本任務無關乎字母大小問題,所以IgnoreCase屬性無需要設置為Ture(當然如果設置為true,對最后結(jié)果也無影響);由于Mutiline屬性保持默認,其值為False,所以整個文本只有一個開始位置和一個結(jié)束位置。
代碼中使用了對象reg的replace方法,它的作用是,將在目標文本中找到的匹配(開始和結(jié)束位置)替換為”@”字符,在這里實際上是插入。然后把修改后的文本返回,重新賦值給字符變量S。
任務2代碼:
Sub test2()
Dim reg, s$
s = "Aaa" & vbLf & "bbb"
Set reg = CreateObject("vbscript.regexp")
reg.Pattern = "^|$"
reg.Global = True
reg.MultiLine = True
s = reg.Replace(s, "@")
MsgBox s
End Sub
討論:
任務2代碼與任務1代碼唯一區(qū)別是修改了mutiline默認屬性,設置為True。這就意為著,該文本的每一行都存在一個開始位置和結(jié)束位置。所以Msgbox最后顯示的結(jié)果為:
@Aaa@
@Baa@
6.應用對象的方法代碼段
VBScirpt正則對象的方法共有三個:你可以根據(jù)任務要求選擇使用一個或多個方法.
(1)TEST方法
語法:Object.Test(string)
Test方法只是簡單測試目標文本中,是否包含正則表達式所描述的字符串。如果存在,則返回True,否則返回False。
例:用代碼檢測用戶的輸入是否是一個電子郵箱。
Sub ChkEmail()
Dim reg, s$
s = InputBox("請輸入一個電子郵箱:")
Set reg = CreateObject("vbscript.regexp")
reg.Pattern = "^\S+@\S+$"
If reg.Test(s) Then
MsgBox "你輸入的電子郵箱格式正確: " & s
Else
MsgBox "你輸入的電子郵箱格式不正確!"
End If
End Sub
討論:
代碼從用戶那里獲得字符串,然后賦值與字符變量S。驗證郵箱的正則表達式非常簡略,元字符序列"\S"表示不是空格的任意一個字符,后面緊跟一個+號表示一個以上字符。這個表達式事實上只驗證了用戶的輸入里,在字符串之間是否有一個@符號。它甚至認為”0@中”都是正確的。下面給出一個更為嚴格的電子郵箱正則表達式:“^[\w.-]+@[\w.-]+$”當然要嚴格按電子郵箱規(guī)范寫出正則表達式,可能就十分復雜,由于我們剛剛接觸正則,就不在詳細討論了。
這里要關注的是,test方法的語法,在方法與正則對象之間也是用英文點號隔開,作為參數(shù),目標字符串用英文括號包圍。在這個例子中,如果Test返回的是true,表示目標文本S中找到了正則模式的匹配。則顯示正確結(jié)果,否則顯示錯誤提示。
(2)Replace方法
替換在目標文本中用正則表達式查找到的字符串。
前面例子中語句體現(xiàn)其語法:s=reg.replace(s,”@”)
后面括號中的參數(shù)S,代表前面代碼中設置的目標文本字符串.也就是正則表達式將要作用的目標文本.”@”是用來替換的字符串參數(shù).前面的s是Replace方法返回的結(jié)果,它是目標文本被替換后的一個副本. 如果沒有找到匹配的文本,將返回與目標文本一樣的一個副本.
下面繼續(xù)討論Replace方法的第二個參數(shù):
例子中"@"是一個字面字符,要用一對雙引號包圍起來。第二個參數(shù)還可以是變量、表達式。如果是變量或函數(shù)則不能用雙引號包圍,這一點和VBA代碼規(guī)則是一致的.
上一章我們知道了如果在正則表達式中使用了元字符序列()括號,那么被圓括號包圍的內(nèi)容會存儲在特殊變量$1中。在有些編程語言中,可以直接在正則代碼外使用$1變量,而VBScript中可以并只可以在Replace方法中,作為第二參數(shù)來調(diào)用。
例子:在目標文本中的數(shù)字數(shù)據(jù)后增加上單位:KG
目標文本:“他們體重分別是:張三56,李四49,王五60?!?/p>
結(jié)果文本要求: “他們體重分別是:張三56KG,李四49KG,王五60KG?!?/p>
正則表達式:(\d+)
替換文本: $1KG
Sub testrep()
Dim reg, s$
s = "他們體重分別是:張三56,李四49,王五60。"
Set reg = CreateObject("vbscript.regexp")
reg.Pattern = "(\d+)"
reg.Global = True
s = reg.Replace(s, "$1KG")
MsgBox s
End Sub
討論:
用正則表達式(\d+),Replace方法將在目標文本中找到三個匹配,其值分別是56,49,60。并分別把每個值保存于每一個匹配對象的$1變量中。
替換文本:”$1KG”表示每一個匹配中的$1變量值與字面字符”KG”聯(lián)結(jié),組成新字符串,用來替換找到的數(shù)據(jù)字符串。
$1是一個很特殊的變量,它由美元符號與數(shù)字編號組成.如果正則表達式中有兩個或兩個以上的捕獲性括號,則按照左括號”(“從左到右順序編號,自動命名為$1,$2,$3….,共支持99組.要指出的是,如果找到多個匹配,那么每個匹配中的特殊變量名是一樣的.這個例中共有三個匹配其值分別為56,49,60.第一個匹配的變量名是$1,第二和第三個匹配的變量名仍然是$1,只是每個匹配中$1保存的值是不一樣的.
最后一點,作為替換參數(shù)的一部分,$1變量與字面字符共同組成替換字符串時,它們之間不用 & 符號連接,并且 $1 必須放在一個雙引號中;而如果是用其它普通變量與字面字符聯(lián)結(jié)組成替換文本時,則必須用 & 符號聯(lián)接,這一點與VBA代碼使用方法相同.
在Replace方法的第二個參數(shù)中,還有幾個很少用到的特殊變量:
一個較特殊的狀況,如果上面所述的特殊變量符不是作為變量使用,而是要以它們作為字面字符的替換文本,那么就要對它們轉(zhuǎn)義,方法是在它們之前加一個美元符號$.如$$&
(3)Execute方法
在目標文本中執(zhí)行正則表達式搜索。
語法:set mh=object.execute(s)
其中mh是用戶自定的對象變量,S是值為目標文本的字符串變量.object是正則對象.
Execute方法會作用于目標文本(S),并返回一個叫作"Matches"的集合對象,在這里是mh.在這個集合對象中包含它找到的所有叫做"Match"的成功匹配對象(Matches集合最多可容納65536個匹配對象). 如果未找到匹配,Execute 將返回空的 Matches 集合。Matches集合有兩個只讀屬性:索引(Item)和成功匹配的次數(shù)(Count).
Matches集合中包含的匹配對象Match有四個只讀屬性:Value/firstindex/length/submatches
值得一提的是,Submatches屬性是一個集合屬性,集合中元素個數(shù)與正則表達式中使用的捕獲性括號的個數(shù)相同,每個元素的值就是括號包圍起來的內(nèi)容.它也有兩個只讀屬性:item和Count
下面用樹狀圖來表示它們之間的關系,并在接下來的內(nèi)容中繼續(xù)逐一討論它們的用法.
<1>Matches集合的Item和Count屬性
利用Matches集合的Item屬性可以得到它包含的每個Match對象;利用Count屬性可以得到成功匹配的個數(shù).
Matches集合對象中元素(成功匹配)的索引編號從0開始.我們可以用遍歷集合的方式或索引方法讀取每一個匹配值.
例:從一段文本中提取所有英文單詞.
目標文本:”蘋果:iphone_5s;諾基亞:Nokia_1020”
結(jié)果要求:分別提取出iphone_5s和Nokia_1020
代碼:
Sub test2()
Dim reg, k, mh, strA$
strA = "蘋果:iphone_5s;諾基亞:Nokia_1020"
Set reg =CreateObject("vbscript.regexp")
reg.Pattern = "\w+"
reg.Global = True
Set mh = reg.Execute(strA)
For Each mhk In mh
Debug.Print mhk.value
Next
End Sub
討論:
通過語句Set mh = reg.Execute(strA),Execute方法返回一個集合對象mh,在這個集合對象里包含兩個匹配對象,代碼中用遍歷方法取出每一個匹配對象的值.
Execute方法返回的集合對象mh,有兩個屬性:
1)Count: Execute方法成功匹配的次數(shù),也可理解為mh集合對象中包含的成功匹配對象的個數(shù).語法:
N=mh.count 本例中n值為2
2)Item: 索引,可以通過索引值,返回集合對象中指定的匹配對象.語法:
Set mhk=mh.item(0)
K=mhk.value
用索引返回第一個Match對象即mhk. 本例中k為第一個Match對象的值(iphone_5s). 同樣的方法可以得到第二匹配的值.
由于Item和Value屬性是集合的默認屬性,所以上面兩個語句也可簡寫為:
K=mh(0)......第一個匹配對象的值(iphone_5s)
M=mh(1)...........第二個匹配對象的值(Nokia_1020)
上面代碼中遍歷集合也可以用索引法遍歷:
For i=0 to mh.count-1
Debug.print mh(i).value
Next i
<2>Match對象的屬性
Execute方法返回的集合對象中包含的也是對象元素,即match對象,match對象有四個屬性:
FirstIndex:匹配對象所匹配字符串的起始位置。
Length:匹配對象所匹配字符串的字符長度。
SubMatches:匹配對象所匹配結(jié)果中的子項集合。
Value:匹配對象所匹配的值。
在本例中:索引為0,即第一個匹配對象的屬性值為:
K=mh(0).value k的值為iphone_5s,value是默認屬性可簡寫為k=mh(0)
sn=Mh(0).firsindex sn的值為3,表示在目標字符串中,位置3上找到該匹配iphone_5s.(位置是從0開始的)
Ln=mh(0).length ln值為9,即iphone_5s的字符長度
3>Match對象的Submatches屬性
匹配對象match的Submatches是一個集合屬性,它包含正則表達式中用圓括號捕捉到的所有子匹配.它為用戶提供了返回$1特殊變量值的方法.
集合Submatches有兩個固有屬性:Count和Item.可以通過Item得到集合中的每個值,它實際就是在正則表達式中用圓括號捕獲的內(nèi)容;Count值是集合中元素個數(shù),實際上就是正則表達式中捕獲性圓括號的個數(shù).
下面給一個實例來說明:
目標文本:給定一個標準郵箱地址:J3721@163.com
要求:從郵箱中分別提取出:用戶名j3721,服務器域名163.com
正則表達式: ^(\w+)@(.+)$
代碼:
Sub test5()
Dim reg, mh, strA$, username$, domname$
strA = "J3721@163.com"
Set reg = CreateObject("vbscript.regexp")
reg.Pattern = "^(\w+)@(.+)$"
Set mh = reg.Execute(strA)
N=mh(0).submatches.count ‘n值等于2
username = mh(0).submatches(0) ‘j3721
domname = mh(0).submatches(1) ‘163.com
End Sub
討論:
正則表達式中,\w+表示匹配@前面的所有英文單詞字符;@后面的點號是一個元字符,表示匹配除換行符外的所有字符之一,后面緊跟+號,即”.+”表示匹配@后面除了換行符外的所有字符.用括號包圍起來,用戶名和域名就會自動分別保存在變量$1和$2中.
前面已經(jīng)知道VBA不能在replace之外直接調(diào)用$1或$2,而這個例子告訴我們可以用match對象的submatches集合屬性來提取.
在這個例子中,execute方法返回的集合對象mh中,mh中只有一個匹配對象Match,即mh(0);mh(0)對象的屬性submatches(0),返回第一個括號中的內(nèi)容,即j3721.而submatches(1),返回第二個括號中的內(nèi)容.submathches集合也有count屬性,所以如果有很多子項需要提取,也可用遍歷或索引方法返回每一個特殊變量值.最后再給一例子:
下面的代碼演示了如何從一個正則表達式獲得一個 SubMatches 集合以及它的專有成員:
正則表達式(一個郵箱地址):
(\w+)@(\w+)\.(\w+)
如果你沒有進一步了解元字符,可能不懂其中含義,不過沒關系,在這里你只要知道,該代碼的任務是顯示電子郵箱,用戶名和組織名.
Function SubMatchTest(inpStr)
Dim oRe, oMatch, oMatches
Set oRe = New RegExp
' 查找一個電子郵件地址
oRe.Pattern = "(\w+)@(\w+)\.(\w+)"
' 得到 Matches 集合
Set oMatches = oRe.Execute(inpStr)
' 得到 Matches 集合中的第一項
Set oMatch = oMatches(0)
' 創(chuàng)建結(jié)果字符串。
' Match 對象是完整匹配 —
retStr = "電子郵件地址是: " & oMatch & vbNewline
' 得到地址的子匹配部分。
retStr = retStr & "電子郵件別名是: " & oMatch.SubMatches(0) ' dragon
retStr = retStr & vbNewline
retStr = retStr & "組織是: " & oMatch. SubMatches(1) ' xyzzy
SubMatchTest = retStr
End Function
Sub SubMatchesTest()
MsgBox(SubMatchTest("請寫信到 。 謝謝!"))
End Sub
如果知道一點英文,理解記憶會更快。
\w
→ word 首字母 w
表示26個英文字符【A-Za-z】以及下劃線【_】和數(shù)字【0-9】的集合,
.Pattern ="\w" 等價于 .Pattern ="[0-9a-z_A-Z]"
其中有英文字符很好理解,因為英語中的word肯定是由英文字母構(gòu)成的。
另外,在VBA編程中,變量還可以含有數(shù)字和下劃線,因此數(shù)字和下劃線也被當做構(gòu)成統(tǒng)一word的要素。
除此之外的其它字符,都不算構(gòu)成word的要素了。
\d
→ digit 首字母 d
表示數(shù)字【0-9】的集合,
.Pattern ="\d" 等價于 .Pattern ="[0-9]"
\s
→ separate 首字母 s 或space、tab、return簡稱str字符的首字母。
表示分隔符號 含space 空格【 】或【char(32)】、回車vbCr【char(13)】、換行vbLf【char(10)】、vbTab【char(9)】等,
全部ASCII碼值為: char(9)、char(10)、char(11)、char(12)、char(13)、char(32)(空格)
分隔符號的單獨分開是\t tab 首字母 vbTab【chr(9)】或 其反集 \T
\v verticaltab 首字母 vbVerticalTab【chr(11)】或 其反集 \V
\f formfeed 首字母 vbFormFeed【chr(12)】或 其反集 \F
\r 回車 return 首字母 r 而在VBA中對應的是:vbCr【chr(13)】或 其反集 \R (Cr是Carriage Return的簡稱,是機械式打字機時代,字車carriage回復return 到最左邊開始的意思 )
蘋果機(MAC OS系統(tǒng)) 采用回車符Cr 表示下一行.
\n 換行 newline 首字母n vbLf【chr(10)】或 其反集 \N
(Lf是Line Feed的簡稱,是機械式打字機時代,回車的同時自動滾進一行的意思 )
UNIX/Linux系統(tǒng)采用 換行符Lf 表示下一行.
\r\n 回車換行 vbCrLf【chr(13) & chr(10)】
Dos和windows系統(tǒng) 采用 回車+換行CrLf 表示下一行,
=================
接下來介紹,對上述幾個常用元序列/集合,使用小寫字母時是有效,含有的意思,
而使用大寫字母時是無效,排除(不含有)的意思,
如:
\W → word 首字母 大寫 W 標記的【英文字母、數(shù)字、下劃線】的序列/集合的反集
小寫字母w .Pattern ="\w" 等價于 .Pattern ="[0-9a-z_A-Z]"
大寫字母W .Pattern ="\W" 等價于 .Pattern ="[^0-9a-z_A-Z]"
2.
\D → digit 首字母 大寫 D 標記的【數(shù)字】的序列/集合的反集
小寫字母d .Pattern ="\d" 等價于 .Pattern ="[0-9]"
大寫字母D .Pattern ="\D" 等價于 .Pattern ="[^0-9]"
3.
\S → separate 首字母 大寫 S 標記的不可見換行字符的序列/集合的反集
小寫字母s .Pattern ="\s" 等價于 含有char 9,10,11,12,13,32
大寫字母S .Pattern ="\S" 等價于 不含有char 9,10,11,12,13,32
=======
以上
\b 和 \B
begin 的首字母 b
意義: 以上述\s separate 集合分隔后得到的每一個 \w word 中的第1個begin字符。
如:
abe sau
dty12 f_34
執(zhí)行小寫字母b .Pattern ="\b." 則得到每一個word的首字母:a s d f
=====
執(zhí)行大寫字母B .Pattern ="\B." 則得到每一個word的首字母以外的字符:b e a u t y 1 2 _ 3 4
====
以上。
補充,該規(guī)則僅對英文word能100%正確作用。
如果對象字符集中出現(xiàn)\W字符即非英文數(shù)字下劃線字符,如漢字或其他符號,
則可能會返回不可預知的結(jié)果。(因為漢字等其它詞匯無法像英文那樣簡單區(qū)分word和word之間的間隔。)
(如同Vlookup函數(shù)中搜尋數(shù)組中沒有正確A-Z排序時可能返回不可預知結(jié)果一樣。)