顯示具有 Regex正規表示式 標籤的文章。 顯示所有文章
顯示具有 Regex正規表示式 標籤的文章。 顯示所有文章

2018/06/06

Boost Regex and Unicode in C++ Builder

Boost - Bast C++ Library
Because "String" default is unicode in C++ Builer 2009 later.

And same std::wstring.

so, We should to use prefix "w" class, like:
wregex, wsmatch etc.

The Sample code below:

2015/10/22

Delphi IDE Search 功能的 Regular Expressions


最近在修改元件的過程中,遇到許多要增加屬性的操作。

比方說操作 Excel 元件時,我們可以這樣寫:
  ExcelWorksheet1.Cells.Item[Y, 3];
  ExcelWorksheet1.Cells.Item[Y, 6];
  ExcelWorksheet1.Cells.Item[Y, 8];

這些上百行有點像又不會太像的程式,我想修改成以下的內容
  ExcelWorksheet1.Cells.Item[Y, 3].Value;
  ExcelWorksheet1.Cells.Item[Y, 6].Value;
  ExcelWorksheet1.Cells.Item[Y, 8].Value;

實除修改時,除了增加滑鼠和鍵盤磨耗率外,對技術力的增加簡單是趨近於零。

這時,有個巧妙的工具可以應用 ── Replace Text (Hot Key = Ctrl + H)。

Replace Text 畫面
我猜猜你會怎麼做:

【選擇大範圍的模糊搜尋,找到目標後,再人工修改。】

實在很苦命。

這時正則表達式(Regular expressions)就很有用了。

Regular expressions 的位置

以上述的例子來說,我可以在 Text to find 輸入
{\.Item\[.+\]}

在 Replace with 輸入
\0.Value

如此一來就變成這樣:

找到了,要修改囉
修改成功!

要注意的是,官方說明的【()】符號並沒有功用,實際應用請直接使用【{ }】符號。

參考資料:


2015/04/21

Delphi XE Regular Expressions 單元中的 Bug

Report #: 87752 TRegEx frees FRegEx while TMatch et al still have a reference to it 這篇中有提到。

在 RegularExpressions 單元有個潛在的bug。 重現的方式也很簡單:
procedure TForm1.Button1Click(Sender: TObject);
begin
  Button1.Caption := TRegEx.Match('one two', '\w+').NextMatch.Value;
end;

會發現Button1.Caption變成空白,而不是預期的"one"。

詳細的解說在:
Bug in Delphi XE RegularExpressions Unit.

解決方式如下:
To fix this bug, delete or rename the two RegularExpressions.dcu files and copy RegularExpressions.pas into your source code folder. Make these changes to both the TMatch and TGroupCollection records in this unit:

  1. Declare FNotifier: IInterface; in the private section.
  2. Add the parameter ANotifier: IInterface; to the Create constructor.
  3. Assign FNotifier := ANotifier; in the constructor’s implementation.

You also need to add the ANotifier: IInterface; parameter to the TMatchCollection.Create constructor.

修改完成後,把Debug和Release後的dcu,覆蓋($BDS)\lib\debug(release)目錄同名檔案即可。

附帶說明,在Delphi XE2以後已經修正了這個Bug,如果你有需要,請再留言索取。

參考資料:

2014/07/30

[RegEx] Delphi XE 增加的 TRegEx 資料整理

原來從 Delphi XE 開始就有內建 RegEx 類別了,現在開始要重新學習了

看來是抄 M$ Framework 抄很大。哈!

有關錢字號「$」的說明:
C# Regular Expressions Substitutions (經常用在 Replacement 中)


2012/12/14

关于在DELPHI6中使用正则表达式的一些心得

转载地址:
http://www.delphibbs.com/keylife/iblog_show.asp?xid=25712
http://blog.csdn.net/senfore/article/details/2154944

一. 工具选择

DELPHI6本身没有处理正则表达式的库,只能找第三方库。在选择方面,我的标准是:

1. 不必向开发环境注册控件
2. 接口简单
3. 符合主流的perl式正则语法
4. 专业,至少应该有个看上去专业的专门网站
5. 免费

目前符合以上标准, 比较好的RegEx类库有TRegExpr ( http://www.regexpstudio.com/ )与PerlRegEx ( http://www.regular-expressions.info/ )。

TRegExpr 是俄国人做的RE类库,应该说是目前国内最主流的免费RegEx类库了。纯DELPHI写成,支持中文,可以选择安装为开发环境控件,也可直接作为类库单 元使用(只有一个主类,一个pas文件)。美中不足是自从2004年后就没有更新了,版本一直是0.9xxx,就是不上1。而且不支持 Lookaround语法(前瞻与回溯功能)

PerlRegEx底层是用C的类库,完全符合PCRE标准(兼容Perl的正则表达式)。 文件结构比TRegExpr复杂一点,包括一个放底层obj文件的子目录和两个接口.pas文件,实际使用时只需要向项目中添加一个单元(当然也可以注册 成为控件)。之前的版本据说对中文支持不够,最新版本我在中文环境下用倒没遇到什么问题。说明文档也声称支持Unicode。

现在我是常 备两个这两个类库,但主要还是用PerlRegEx。除了迷信最后更新日期与C的执行效率外。还看中了RegexRubby这个基于同一套C类库的 RegEx编写工具,以及PerlRegEx提供了一个study方法,声称可以对正则式做点前期编译,提高执行效率。

=========================================================================
二 使用方法:

解 压了PerlRegEx包后,如果不想注册控件,除了PerlRegEx.pas、CHelpers.pas和PCRE目录外,其他的东西可以建个隐藏目 录搁置起来(没认真阅读用户协议,不知道能不能随便删。。。)。维持这两个文件与PCRE的目录结构不要变。使用时只需要把PerlRegEx.pas添 加进项目,在单元中uses PerlRegEx就可以了。

PerlRegEx提供了TPerlRegEx类。主要用法是:

RegEx : TPerlRegEx;
....
RegEx := TPerlRegEx;
try
  RegEx.Subject := '要匹配的正文';
  RegEx.RegEx := '正则表达式';
  if RegEx.Match then ....
finally
  RegEx.free
end;

如果要多次匹配并做一些处理,可以:
Matched : boolean;
....
RegEx.Match;
while RegEx.FoundMatch do
begin
  ....
  RegEx.MatchAgain;
end;

如果要替换匹配到的内容,可以
RegEx.Subject := '要匹配的正文';
RegEx.RegEx := '正则表达式';
RegEx.Replace := '替换的字符串'
if RegEx.Match then RegEx.ReplaceAll;  //结果在RegEx.subject
或者 if RegEx.Match then Result := RegEx.Replacement;

匹配到的字符串放在RegEx.MatchedExpression中,长度在RegEx.MatchedExpressionLength中,上一次匹配的结束位置在RegEx.Stop中

匹配到的子串放在RegEx.SubExpressions[i]中,子串个数在RegEx.SubExpressionCount中。

如果正则式很复杂而且常用,可创建一个生存期相对长的TPerlRegEx实例.设置好RegEx属性后,使用.Study方法对正则表达式进行预处理.据帮助文档说,文档资料会大大提高效率.

详情可参考文档。有一点文档上没有提到(又或者我看漏了),在第一次匹配之后,如果没有重新赋值subject,下一次匹配无论用Match或者MatchAgain,都是从上次的结束位置开始。所以如果要重新开始匹配,应先把RegEx.Start := 0;

==========================================================================
三. 使用和编写正则表达式要点

使用正则表达式,通常是用作三种用途:校验字符串,提取信息,处理字符串.

当 用作校验时,通常是对正文整体校验,例如通常是判断正文是否正确的邮件地址,而不是判断正文是否含有正确的邮件地址.因此应在正则表达式的两端加上行开始 锚点^与行结束锚点$.如果待校验的文字允许两端有空格,则应该在锚点前后用' *'或'/s*'(允许空格与TAB)匹配进去.

设计正则表达式的要点在于分段.对要匹配的内容分好段,就能够容易地各个击破.通常在要匹配的文字中会有一些分段的提示,例如逻辑上的单位、重复出现的模式或者不能连续重复出现的字符(串)。

以设计校验输入数字的正则条件为例,可以先列出符合条件的情况:
1234 / 12.34 / -12.34 / 12.3e4 / 12.3e-4 / .12E-34
可以看出,逻辑上的单位有:符号,整数部分,小数点,小数部分,e(或E),指数符号,指数部分
技术上的分段标志有:

符号:在开始与E后面各可能出现一次
小数点:只能出现一次,若出现,其后必须有小数部分。
e:只能出现一次,若出现,其后必须有指数部分。

所有“若出现,其后必须有。。。”的都可以考虑分为一组。可得初步方案: [+/-]?/d*(/./d+)?([Ee][+/-]*/d+)?

但 这个设计有问题,前半段的 /d*(/./d+)? 是可以匹配空串的,而需求是如果有整数部分,则小数部分可选。如果无整数部分,则必须有小数部分,直观的做法是改为(/d+(/./d+)?|/. /d+)。再认真观察一下,可以发现这个选择式无论任何情况,都是以/d+结尾,而我们实际上并不关心这个/d+是匹配到整数部分还是小数部分,至于前面 的小数点与整数部分都是可选的。因此,这部分可以改写为 /d*/.?/d+

所以最终的校验式是:^ *[+/-]?/d*/.?/d+([Ee][+/-]*/d+)? *$

使 用正则表达式提取信息是一个难点,但也是体现正则表达式强大实力的一个方面。提取信息的正则表达式必须要考虑四个方面:不误判(应该有一定语法检验能 力),不漏判,子串能匹配到正确位置。一些结构复杂或具有循环结构的正文,可能需要多次处理或使用开发语言的循环结构来辅助提取。具体技巧我现在还觉得比 较模糊,以下仅举几个例子:

1. 查找并分析 XX1>XX2,<,=,!,空格,TAB符号的任何字符串,式子两端与元素之间允许有空格或TAB

由 于这个不等式可能在上下文中,我们需要先在正文中把合语法的不等式隔离出来,否则下面的循环部分就会匹配到下一条不等式的部分。在这个例子中还算简单,找 到 '/b[^<>=!/s]+((不等符号)[^<>=!/s]+)+/b' 就可以了(其中不等符号在下面解释)。但这样只能匹配到整个式子而不能分别提取式子中的子串信息,当出现(...)+时,对应子串内容是只是最后一个匹配 到的串。

对每个匹配到的结果,因此这里需要分开两次提取,第二次需要使用循环来辅助。

先取最开始的子串,这个很容易,直接 '^/s*([^<>=/s]+)'就可以了,注意^ *是为了去掉开头多余的空格与TAB。真正的XX1在匹配到的子串1中。

接 着开始分析 '((不等符号)[^<>=!/s]+)+' 部分。整个(...)+结构需要在外部用开发语言的循环来逐次提取。先列出合法的不等符号:>=,>,=,<=,<,<& gt;,==,!>,!<,!>=,!<=,!=。因此不等符号部分应该是(!?>=?|!?& lt;=?|!?==?|<>)。

因此,要分析篇正文,就需要:
1)A匹配 '/b[^<>=!/s]+(/s*(!?>=?|!?<=?|!?==?|<>)/s*[^<>=!/s]+)+/b' 找出不等式。
2)    对每个A匹配结果, B匹配'^/s*([^<>=!/s])',提取子串1记录为变量名称。
3)    接着B匹配'/s*(!?>=?|!?<=?|!?==?|<>)/s*([^<>=!/s]+)',提取子串1记录为符号,子串2记录为变量名称。
4)    从3)开始循环直到找不到B匹配结果
5)从1)开始循环直到找不到A匹配结果

2. 提取电话号码

这 是不久前帮朋友做的一个小程序。事情是这样的:他的公司需要撒网式找澳大利亚酿酒公司合作伙伴,他的任务就是把网上查到的酿酒公司的联系方式记录入库。记 录联系方式的数据库是把公司名称,地址,电话号码,传真号码,邮箱等信息分开不同字段储存的。于是他必须用鼠标在网页准确选下各种信息然后粘贴到数据表 中,不但工作效率低,而且据说由于鼠标精确动作太多,手腕酸得不得了。于是找我帮忙写个小程序,需求是他可以把联系方式部分整个复制下来,我的程序自动提 取出有关信息。以下是提取电话号码信息功能的设计过程:

我看了一下联系方式的可能情况,发现有时里面会包括多个电话号码,而朋友的数据库只记录一个号码。因此我决定把他选定文本中所有电话号码都提取出来,列在一个ComboBox中让他选择。在正文中标记为“Phone”或"Ph"或"P"的优先列在前面。

电话号码的写法五花八门,先考虑电话的标记,一般有以下几种:
Phone, Phone:, (Phone), P, P-, PH 等等
因 此可把匹配标记的正则表达式设计为 '(?-i)(?:/(?Phone|Ph?)[-:]?/s*/)?)'。这种写法有个缺陷是无法保证两边括号能匹配(例如能匹配到 '(Phone:')。但在这里的目的并不是校验,括号不匹配并不影响我提取电话号码,只求简单写成这样就够了,否则就要写 成:'(?:Phone|Ph?)[-:]?|/((?:Phone|Ph?)[-:]?/s*/))' ,麻烦得多。

然后考虑电话号码本身,一个完整的固定电话号码可能是这样的:
+61 2 1234 5678 , (61 2) 1234 5678 , (61-)2-12345678, 61 (0) 2 12345678
而也可能省略国家代码(+61)或洲区号(02)简写成
02 1234 5678 , 1234 5678, 2-1234-5678
也有可能不按主号码四字一断的做法,写成
02 123 456 78 等等

构建正则表达式的过程如下:

匹 配国家代号:(?:[+( ]*61[-) ]*)?  可以看出,这个式子如果用来校验是不合格的,它能匹配到'(++61-)-'这样的正文。但我在这里是为了提取公司网页上的信息,公司不会在自己的联系 方法信息里放入这样的乱码。提取信息时,根据需求,在不误判的前提下可以假定输入信息不会出现太离谱的错误。

匹配区号:(?:/(? *0?/)? *(/d) *[-)]? *)?  同上,这个式子也可能匹配到不合法的正文。这里如果把区号与主体号码合并处理会简单很多。但我在这里想把区号提取出来,作为判断省份的一个依据。

匹 配电话号码主体:(?:/d{5,}(?:[ -]/d+)*|/d{1,4}(?:[ -]/d+)+) 如果仅考虑匹配电话号码,用/d*(?: [ -]/d+)*就行了。但澳大利亚的邮政编码刚好是四位数字,而且地址中的信箱号有可能是3到4位数字。因此这里用了个麻烦的写法,如果连续数字小于5 位,则后面必须跟一个连接号或空格,然后再跟数字,才能匹配到。

因此优先选取的号码的正则表达式是:(?-i) (?:/(?Phone|Ph?)[-:]?/s*/)?)((?:[+( ]*61[-) ]*)?(?:/(? *0?/)? *(/d) ?[-)]?/s*)?(?:/d{5,}(?:[ -]/d+)*|/d{1,4}(?:[ -]/d+)+))
电话号码在子串1,区号在子串2

第 一轮扫描正文,一边找到匹配,一边把其替换成''。完成后,就可以用((?:[+( ]*61[-) ]*)?(?:/(? *0?/)? *(/d) ?[-)]?/s*)?(?:/d{5,}(?:[ -]/d+)*|/d{1,4}(?:[ -]/d+)+)) (去掉了匹配电话标志部分)对替换后的正文,找出所有没有电话标志,但符合格式的子串。  

2010/01/19

C++ Builder 全系列 我猜 無法安裝TPerlRegEx

最近在嚐試安裝TPerlRegEx(2008年的Final版)元件在C++ Builder上,安裝平台是:BCB6, CB2010,但卻都會發生異常的錯誤訊息。

可能針對的是Delphi版設計的吧,目前還找不到可以安裝在C++ Builder上的辦法
在Delphi社區已經被研究到爛的東西,想不到在cb上卻無法順利執行,真是嘔啊!

真的要找時間好好來研究Boost::Regex了。反正也是走正統Perl語法,哈!

2010/01/18

BCB6 + Boost::Regex

老東西還是能玩出新花樣吧
最近在K字串比對的花招,發現原來 C++ Builder 2010 有提供Boost類組來處理文字技術
那麼,使用Regex應該不是什麼難事吧

目前應用在delphi產品中很出名的TPerlRegex,新的版本(2008年出的)並不能安裝在 C++ Builder 2010上,當然,也不能安裝在BCB6囉!

目前唯一能用的是TPerlRegex 2005年推出的舊版本,雖然我不知道這其中多了什麼東西,但能用新的當然是越新越好啦!哈哈!

因為 C++ Builder 2010的Boost安裝程式不支援 BCB6 安裝(廢話),所以只能到 Boost 的官方網站上下載最新的版本。

咦?有1.41版耶!這足足比 CB2010 所提供的1.35足足多了近「0.1」的版次,想必功能應該更齊全吧!(其實根本用不到這麼多,只是簡單的文字比對而已……)

在 BCB6 上編譯時,發現沒問題!安裝也OK。但在include boost後測試demo,卻現在 BCB6 找不到1.40的檔案!還真是奇怪的問題,可能是1.41還在測試階段的關係吧,沒把安裝程式包好。

於是改用1.40版本,果然一切正常,花了一個星期的時間研究「如何安裝」…終於可以開始實測囉!!!

2010/01/14

這…應該是與2010的計畫無關吧

好…好吧
我承認我又開始走偏路了! XD

最近因為公司新開案的內容,有用到關於字串的驗証
字數有多有少,中間還有一槓…

一想就覺得是件需要用到大量程式碼的東西…

嗯…何不使用正規表示式呢?

於是又把精力花在正規表式上面了……

我想,最近研究這個的時間應該會比我寫程式碼的時間還要多吧,哈哈!