BCB5 使用 Regular Expression

過去為了工作需要,陸續在 BCB5 加進了支持 Unicode、資料庫的元件,當時還說未來最希望找到支援 Regular Expression (正規表達式,底下簡稱 RE) 的元件。前二天要把一個 perl 的程式移植到 BCB 來,因為該 perl 程式大量使用了 RE ,所以不得不停下工作,開始測試支援 RE 的資料。

這幾年的寫程式經驗中,perl 曾把我帶到另一個領域,最令人激賞的就是 perl 的 hash 及 RE,因為工作中有許多處理文字的問題,這些用 c++ 來寫非常不便,但 perl 的魔力卻讓這些事變的簡單許多,若不考慮圖形介面與效率的程式,perl 幾乎就是我隨手寫程式的工具了。

這幾月又重拾 BCB 寫程式,也開始用 set 及 map 來取代 perl 的 hash(BCB 6 內含的 STLport 已有 hash_set 及 hash_map,應該更好用,BCB5 還要自己去找來安裝),如今 BCB 找到了內嵌式的資料庫,若再加上 RE 的功能,那真是如虎添翼,寫起程式一定是更加得心應手了。

我找到幾個相關的資料,網址如下:

TRegExpr: http://www.regexpstudio.com (本站有些網址連結都會少了開頭的 www,若發現連結失敗,要自行加上 www)

PCRE: http://www.pcre.org

TPerlRegEx: http://www.regular-expressions.info/delphi.html

TropicSoft: http://www.tropicsoft.com/Components/RegularExpression/index.html

Regex++: http://ourworld.compuserve.com/homepages/John_Maddock/regexpp.htm

最初是找到的 TRegExpr 只有一個 pascal 檔,很容易使用,也很方便,但因為是 pascal 寫的,我擔心效率不夠好,就繼續研究其他的。

PCRE 好像是 c++ 寫的,效率應該很好,有一些元件都是使用它來包裝的。我後來有發現 BCB5 好像就有內含,不過用起來似乎很麻煩,我就暫時放棄學習。

TPerlRegEx 據說就是用 PCRE 包裝的,而且他名稱上有 perl,深得我心,不過使用上一直很不順,結果還會有問題,所以也暫時放棄。

TropicSoft 那一個我沒有試,因為它要安裝,所以我只是下載回來放著。

Regex++ 據說效率很好,使用 c++ 撰寫的,不過因為他是用 template 的方式設計,而我對 STL 研究不多,我比較習慣用 VCL 提供的元件。

花了不少時間研究後,最後還是先決定使用 TRegExpr,因為工作結案有時間壓力,沒法做太多研究。

TRegExpr 試起來效果不錯,基本功能都成功,底下就簡介幾個研究出來的功能。

■ 使用方法

把 RegExpr.pas 加入 project 中,先 compiler 它,讓它產生 RegExpr.hpp,並在要使用的程式中加入底下這一行:

#include "RegExpr.hpp"

■ 宣告

TRegExpr 可以宣告後使用,也可以利用一些隱含宣告的函式來執行,若要自行宣告物件,可用如下方法:

TRegExpr * regex = new TRegExpr;
....
delete regex;

■ 比對 Match

1.直接比對

if(ExecRegExpr("\\d", "My id is 1234.")) ShowMessage("match");

這類似 perl 的

$_ = "My id is 1234.";
if(/\d/) {print "match";}

注意:在 c++ 中,\ 符號要改用 \\,才不會出錯。

2.使用物件操作

regex->Expression = "(\\d+)";
regex->InputString = "abc123ijk456xyz";
if(regex->Exec())
{
do
{
ShowMessage(regex->Match[1]);
} while(regex->ExecNext());
}

類似 perl 這二行:

$_ = "abc123ijk456xyz";
while(/(\d+)/g) { print $1;}

簡單介紹幾個屬性與方法:

regex->InputString 輸入的原始字串
regex->ExecRegExpr 要比對的格式

regex->Exec() 在 InputString 比對 ExecRegExpr
regex->Exec("原始字串") 也可由參數傳入要比對的字串
regex->ExecNext() 進行下一筆比對

比對之後:

regex->SubExprMatchCount 大概是有幾個括號引用, 例如 "..(\d)..(\d).." 表示有二個括號
regex->Match[n] 每一個符合字串的內容
regex->MatchPos[n] 每一個符合字串的位置
regex->MatchLen[n] 每一個符合字串的長度
n 的數字類似 perl 的 $1 , $2, , 不過 0 則表示全部, 例如 ".(.)." , $0 表示全部的三個字, $1 是中間的字.

■ 分割 Split

1.直接處理

TStringList * slResult = new TStringList; // 存放結果用的
SplitRegExpr("\\s*,\\s*", "abc ,123 , xyz", (Classes::TStrings *) slResult);

類似 perl 這一行:

@result = split(/\s*,\s*/,"abc ,123 , xyz");

2.使用物件操作

TStringList * slResult = new TStringList; // 存放結果用的
regex->Expression = "\\s*,\\s*";
regex->Split("abc ,123 , xyz", (Classes::TStrings *) slResult);

■ 取代 Replace

1.直接處理

AnsiString sTmp = ReplaceRegExpr ("\\d(\\d)(\\d)", "phone 035 and 076 bye", "$2:$1", true);

傳回 sTmp = "phone 5:3 and 6:7 bye"

類似 perl 這二行:

$_ = "phone 035 and 076 bye";
s/\d(\d)(\d)/$2:$1/g;

若最後參數為 false , 表示 $1, $2 不代表正規式字串中的括號內容。

傳回 sTmp = "phone $2:$1 and $2:$1 bye"

注意:這裡的取代是全部取代,類似 perl 的 /g 參數。所以若要做單一取代,要自己在正規式中寫清楚。

2.使用物件操作

regex->Expression = "\\d(\\d)(\\d)";
AnsiString sTmp = regex->Replace("phone 035 and 076 bye", "$2:$1",true);

有了以上這些功能,BCB 要處理許多資料真的會方便很多,只是不知 TRegExpr 效率如何?若有機會,還是要試試 PCRE 的相關元件。

重要度:
文章分類:

回應

版大您好,再請教一下,TRegExpr它有內建比對字串後再比數字大小的功能呢?

我不太懂 "比對字串後再比數字大小的功能" 的意思.

所以我大概沒用過這類功能, 不過我也想了解一下這是什麼意思?

比方說像是
"1-6"
我想比較1、3碼的數字大小
不知道這方面的功能Regex是否可以辦到呢?

我大概會這樣做, 不知這是不是你想要的功能?

regex->Expression = "(\\d+).(\\d+)";
regex->InputString = "1-6";
if(regex->Exec())
{
int a = AnsiString(regex->Match[1])).ToInt();
int b = AnsiString(regex->Match[2])).ToInt();

if(a>b) ....;
else .....;
}

沒錯!
就是這個!

不過看來Regex是沒有比大小功能的
還是得再用c++來比較數值大小 ^ ^

謝謝版大囉!

發表新回應