正則表達式是一種模式匹配形式,它通常用在處理的文本程序中。比如我們經常使用的grep工具,還是perl語言都使用了正則表達式。傳統的C++處理正則表達式是非常麻煩的,這也成為很多其他語言愛好者的笑柄,現在情況不一樣了,因為有了boost。
Boost是一個基于Template的開發源代碼庫,在這個庫中有很多子庫用來高效處理各方面的問題,比如字符串拆分,格式化,線程等等,Boost對于每一個C++愛好者都是應該了解的,對于C++ Builder用戶如果能在熟練使用VCL的情況下再熟練使用Boost,我想一定如虎添翼。
一般來說,使用Boost是非常簡單,和使用其他STL庫沒有太大區別,但使用Boost的正則表達式庫則不那么容易,因為這個庫還需要我們單獨編譯,下面我將詳細介紹如何使用。
如果你還不知道或者還沒有Boost的話,你可以去www.boost.org下載最新版本,作者使用的是1.30版本。將下載下來的zip包[1]解壓到任何你喜歡的目錄,比如D:\boost。
編譯正則表達式庫
前面已經提到,這個庫需要我們單獨編譯才能使用,為什么不編譯好一起發布呢?主要是考慮到不同的編譯器需要不同的鏈接庫文件和鏈接庫太大了。在命令行下,進入[%Boost]\Libs\RegEx\Build目錄,直接敲入make –fbcb6.mak命令開始編譯,這里請大家注意了,如果你的計算機上同時安裝了BCB5,請一定要把path設置成為BCB6的bcc32.exe程序所在的目錄,否則可能使用BCB5的make程序,這樣雖然能編譯但最后不能使用。
編譯過程相當耗時,你需要耐心等待,最終編譯完成,會在[%Boost]\Libs\RegEx\Build目錄生成一個BCB6目錄,在這個目錄生成了很多lib文件和dll文件,把所有dll文件復制到windows系統目錄,所以lib文件復制到bcb6\lib目錄。如果你不想這么麻煩的復制文件,可以在編譯時加入install參數,就像這樣make –fBcb6.mak install,不過作者還是比較喜歡前一種方式,這樣我可以知道到底生成了什么文件。現在編譯已經完成了,你可以體現boost的神奇魅力了。
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
int main()
{
using namespace boost;
using namespace std;
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
string s="<a href=\"index.html\"><img src=\"logo.gif\"></a>";
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
int c;
cin>>c;
return 0;
}
設置BCB6 Project屬性的Lib Path和Include Path為你安裝boost的目錄,運行你會看到結果:
index.html
可以看到index.html已經從字符串中提出出來了,那么為什么會是這樣呢?
代碼的核心部分是:
regex expression("\\s+href\\s*=\\s*\"([^\"]*)\"",regbase::normal|regbase::icase);
它用來設置如何匹配字符串,上面亂七八糟的字符串很難看懂,如果不了解正則表達式的書寫規則,上
面代碼可以和天書媲美。
regbase::normal|regbase::icase 是解析參數設置,具體可以參考boost幫助文檔。
正則表達式的書寫規則
具體的書寫規則,大家可以參看boost的文檔,我這里做一下簡要說明:
. (dot)
用來匹配任何一個字符,但不包括新行上的字符
*
閉包,任意有限次的自重復連接
+
有限次自重復連接,但至少出現一次
{}
指定可能的重復次數
例如:
ba* 匹配 b ba baa baaa等
ba+ 匹配 ba baa baaaaaaaaa等
ba{1,5} 匹配 ba baa baaa baaaa baaaaa
\
轉義字符,有很多用途,根據參數設置而變化,最常見的就是類似于c語言\的用法
\s
匹配空格
\w
匹配一個單詞
\d
匹配數字
()
有兩種用法:
1是合并的作用,例如(ab)*匹配ab abab ababab等
2是確定匹配,也就是說在()中的字符將被最終拆解出來
根據上面這張表,我們可以很容易知道前面的那段天書如何解釋。
一個實際的例子
前一段時間在CSDN上有一篇帖子,問題是有一種文件結構如(類似):
@People{
Age=19
Speek=”Hay,{name},how are you”
}
問如何拆分字符串得到@后面的名字,=兩邊的屬性名和屬性值,引號里{}種的名字。
解決這個問題用正則表達式再合適不過了。
根據分析,我們可以這樣構造匹配規則:
"@(.*?)\s*\\{" 匹配@開始的字符創,后面兩種類型如何構造匹配規則留給大家思考吧。
這樣我們可以輕易拆解這個例子。
性能分析
通過上面的討論,大家已經了解到boost的強大威力,那個性能又如何呢?為此我們再實際來拆分一個
復雜的html代碼,看看到底需要花費多少時間。
為了節省篇幅,這里就不列出html代碼了,不過可以告訴大家,這是一個又Word生成的大小為186K
的html文件,這個文件中用到了很多<table>標簽,所以我這里測試就來拆分所有<table>標簽的
width屬性。測試代碼如下:
#include<deque>
#include<iostream>
#include<algorithm>
#include<boost/regex.hpp>
#include<vcl.h>
int main()
{
using namespace boost;
using namespace std;
TStringList* html=new TStringList();
html->LoadFromFile("D:\\1.htm");
regex expression("\\s+width=([^\"]*)\s+",regbase::normal|regbase::icase);
DWORD start=GetTickCount();
for(int n=0;n<html->Count;n++)
{
string s=html->Strings[n].c_str();
deque<string> result;
regex_split(std::back_inserter(result),s,expression);
copy(result.begin(),result.end(),ostream_iterator<string>(cout,"\n"));
result.clear();
}
start=GetTickCount()-start;
delete html;
cout<<start;
int c;
cin>>c;
return 0;
}
輸出結果為671毫秒,拆分得到1072個width屬性值,我們可以看到boost的效率是非常高的,雖然與一些角本語言比起來解析速度還是慢,但已經可以滿足大多數編程要求了。另外作者的計算機配置并不是非常高,相信拿到現在任何一臺主流配置的計算機上都會優于作者的結果。
結束語
其實上面的強大威力只是boost的冰山一角,如果你不自己去體會,你很難想象到boost的強大威力。在boost里還有很多使用的庫,比如格式化輸出,字符串拆解,類型轉換等,這些庫使用起來也比較方便,大家可以自行參考boost文檔。在這些庫中還有兩個庫需要自行編譯,他們是Python和thread庫,而且這些庫的編譯需要專門的工具Jam,所以我們在編譯這些庫的時候還要編譯jam工具,而編譯jam工具也不是一件快樂的事情,麻煩同樣出現在如果你安裝了多個編譯器,如果讀者有興趣可以自己試一下。
不過BCB6并不支持全部boost庫,從boost提供的編譯器支持表可以看到[2],BCB6還是有相當多的庫不支持的,支持最好的是gcc/g++的編譯器,但也不是全部支持。希望borland下一個將要發布的C++編譯器可以支持更多C++標準。
[1] 其實還有其他類型的包,但在windows系統下,你最好下載zip包
[2] Boost提供的編譯器支持表是針對BCB5的,對于BCB6的支持作者并沒有詳細測試,如果讀者有興趣可以自己測試boost附帶的測試代碼。
根據網上各種文檔整理而成.=號兩邊要空格的問題折磨了我好久.
1:安裝
先檢查是否安裝CVS包
#>rpm -qa|grep cvs
沒有安裝的話,用下面2種方法安裝
(1):在安裝linux的時候可以選擇安裝CVS包
(2):另外下載CVS RPM包 自行安裝
2:建立cvs用戶和組
#> groupadd cvs
#> useradd -g cvs -G cvs –d /cvsroot cvsroot
#> passwd cvsroot
更改目錄屬性
chmod –R 770 /cvsroot
3:建立CVS服務
#more /etc/services | grep cvspserver
看看是否有
cvspserver 2401/tcp #CVS client/server operations
cvspserver 2401/udp #CVS client/server operations
如果沒有需要到/etc/service文件中增加
建立#vi /etc/xinet.d/cvspserver 文件內容如下
service cvspserver
{
disable = no
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/bin/cvs
server_args = -f --allow-root=/cvsroot pserver
}
該文件有特別要注意的地方,所有=號兩邊都需要空一個空格,除了"root=/cvsroot" 所有要空格的地方,不要多加空格.否則會有CVS服務不能啟動的問題
切換到cvsroot用戶
#cvs -d /cvsroot init
然后重新啟動xinetd服務或者重啟動機器
#service xinetd restart
然后用
#netstat -l | grep cvspserver
or
#netstat -l | grep 2401
看是否有下面tcp 0 0 *:cvspserver *:* LISTEN
說明已經正常啟動,沒有的話請重新檢查配置過程是否有錯誤或者遺漏。最后還必須檢查防火墻的設置,把2401端口打開。
4:用戶管理
CVS默認使用系統用戶登錄,所有系統用戶都可以登陸,但是這樣對系統不安全,我們需要獨立的用戶管理.CVS用戶名和密碼保存在CVSROOT目錄下的passwd文件中.格式
用戶名:密碼:系統用戶
#htpasswd passwd username
用來設置用戶密碼并保存到passwd文件中.
然后需要關閉系統用戶登陸使用cvs的權限,CVSROOT目錄下的config文件,把#SystemAuth=no的#去掉就可以了.
測試登陸
#cvs -d “:pserver:username@127.0.0.1:/cvsroot” login
ok
5 :源代碼倉庫的備份和移動
基本上,CVS的源代碼倉庫沒有什么特別之處,完全可以用文件備份的方式進行備份。需要注意的只是,應該確認備份的過程中沒有用戶提交修改,具體的做法可以是停止CVS服務器或者使用鎖等等。恢復時只需要把這些文件按原來的目錄結構存放好,因為CVS的每一個模塊都是單獨的一個目錄,與其他模塊和目錄沒有任何瓜葛,相當方便。甚至只需要在倉庫中刪除一個目錄或者文件,便可以刪除該模塊的一些內容,不過并不建議這么做,使用CVS的刪除功能將會有一個歷史記錄,而對倉庫的直接刪除不留任何痕跡,這對項目管理是不利的。移動倉庫與備份相似,只需要把該模塊的目錄移動到新的路徑,便可以使用了。
如果不幸在備份之后有過一些修改并且執行了提交,當服務器出現問題需要恢復源代碼倉庫時,開發者提交新的修改就會出現版本不一致的錯誤。此時只需要把CVS相關的目錄和文件刪除,即可把新的修改提交。
6.更進一步的管理
CVSROOT目錄下還有很多其他功能,其中最重要的就是modules文件。這個文件定義了源代碼庫的模塊,下面是一個例子:
代碼: |
Linux Linux
Kernel Linux/kernel |
這個文件的內容按行排列,每一行定義一個模塊,首先是模塊名,然后是模塊路徑,這是相對于CVS根目錄的路徑。它定義了兩個模塊,第一個是Linux模塊,它位于Linux目錄中,第二個是Kernel模塊,這是Linux模塊的子模塊。
modules文件并非必須的,它的作用相當于一個索引,部分CVS客戶端軟件通過它可以快速找到相應的模塊,比如WinCVS。
7.協同開發的問題
默認方式下,CVS允許多個用戶編輯同一個文件,這對一個協作良好的團隊來說不會有什么問題,因為多個開發者同時修改同一個文件的同一部分是不正常的,這在項目管理中就應該避免,出現這種情況說明項目組內部沒有統一意見。而多個開發者修改文件的不同部分,CVS可以很好的管理。
如果覺得這種方式難以控制,CVS也提供了解決辦法,可以使用cvs admin -l進行鎖定,這樣一個開發者正在做修改時CVS就不會允許其他用戶checkout。這里順便說明一下文件格式的問題,對于文本格式,CVS可以進行歷史記錄比較、版本合并等工作,而二進制文件不支持這個操作,比如word文檔、圖片等就應該以二進制方式提交。對于二進制方式,由于無法進行合并,在無法保證只有一個用戶修改文件的情況下,建議使用加鎖方式進行修改。必須注意的是,修改完畢記得解鎖。
從1.6版本開始,CVS引入了監視的概念,這個功能可以讓用戶隨時了解當前誰在修改文件,并且CVS可以自動發送郵件給每一個監視的用戶告知最新的更新。
8.建立多個源代碼倉庫
如果需要管理多個開發組,而這些開發組之間不能互相訪問,可以有2個辦法:
a.共用一個端口,需要修改cvspserver文件,給server_args指定多個源代碼路徑,即多個—allow-root參數。由于xinetd的server_args長度有限制,可以在cvspserver文件中把服務器的設置重定向到另外一個文件,如:
代碼: |
server = /home/cvsroot/cvs.run |
然后創建/home/cvsroot/cvs.run文件,該文件必須可執行,內容格式為:
代碼: |
#!/bin/bash
/usr/bin/cvs -f \
--allow-root=/home/cvsroot/src1 \
--allow-root=/home/cvsroot/src2 \
pserver |
注意此時源代碼倉庫不再是/home/cvsroot,進行初始化的時候要分別對這兩個倉庫路徑進行初始化,而不再對/home/cvsroot路徑進行初始化。
b.采用不同的端口提供服務
重復第2步和第3步,為不同的源代碼倉庫創建不同服務名的啟動腳本,并為這些服務名指定不同的端口,初始化時也必須分別進行初始化。
摘要:
是誰"偷偷的"用了那么多空間呢(本來有幾十個G的Free磁盤空間的)?
檢查數據庫表空間占用空間情況:
SQL> select tablespace_name,sum(bytes)/1024/1024/1024 GB
2 from dba...
閱讀全文
最近在配置MQ,記下了一些常用的MQ命令,如下:
創建隊列管理器
crtmqm –q QMgrName
-q是指創建缺省的隊列管理器
刪除隊列管理器
dltmqm QmgrName
啟動隊列管理器
strmqm QmgrName
如果是啟動默認的隊列管理器,可以不帶其名字
停止隊列管理器
endmqm QmgrName 受控停止
endmqm –i QmgrName 立即停止
endmqm –p QmgrName 強制停止
顯示隊列管理器
dspmq –m QmgrName
運行MQ命令
runmqsc QmgrName
如果是默認隊列管理器,可以不帶其名字
往隊列中放消息
amqsput QName QmgrName
如果隊列是默認隊列管理器中的隊列,可以不帶其隊列管理器的名字
從隊列中取出消息
amqsget QName QmgrName
如果隊列是默認隊列管理器中的隊列,可以不帶其隊列管理器的名字
啟動通道
runmqchl –c ChlName –m QmgrName
啟動偵聽
runmqlsr –t TYPE –p PORT –m QMgrName
停止偵聽
endmqlsr -m QmgrName
下面是在MQ環境中可以執行的MQ命令(即在runmqsc環境下可以敲的命令)
定義持久信隊列
DEFINE QLOCAL(QNAME) DEFPSIST(YES) REPLACE
設定隊列管理器的持久信隊列
ALTER QMGR DEADQ(QNAME)
定義本地隊列
DEFINE QL(QNAME) REPLACE
定義別名隊列
DEFINE QALIAS(QALIASNAME) TARGQ(QNAME)
遠程隊列定義
DEFINE QREMOTE(QRNAME) +
RNAME(AAA) RQMNAME(QMGRNAME) +
XMITQ(QTNAME)
定義模型隊列
DEFINE QMODEL(QNAME) DEFTYPE(TEMPDYN)
定義本地傳輸隊列
DEFINE QLOCAL(QTNAME) USAGE(XMITQ) DEFPSIST(YES) +
INITQ(SYSTEM.CHANNEL.INITQ)+
PROCESS(PROCESSNAME) REPLACE
創建進程定義
DEFINE PROCESS(PRONAME) +
DESCR(‘STRING’)+
APPLTYPE(WINDOWSNT)+
APPLICID(’ runmqchl -c SDR_TEST -m QM_ TEST’)
其中APPLTYPE的值可以是:CICS、UNIX、WINDOWS、WINDOWSNT等
創建發送方通道
DEFINE CHANNEL(SDRNAME) CHLTYPE(SDR)+
CONNAME(‘100.100.100.215(1418)’) XMITQ(QTNAME) REPLACE
其中CHLTYPE可以是:SDR、SVR、RCVR、RQSTR、CLNTCONN、SVRCONN、CLUSSDR和CLUSRCVR。
創建接收方通道
DEFINE CHANNEL(SDR_ TEST) CHLTYPE(RCVR) REPLACE
創建服務器連接通道
DEFINE CHANNEL(SVRCONNNAME) CHLTYPE(SVRCONN) REPLACE
顯示隊列的所有屬性
DISPLAY QUEUE(QNAME) [ALL]
顯示隊列的所選屬性
DISPLAY QUEUE(QNAME) DESCR GET PUT
DISPLAY QUEUE(QNAME)MAXDEPTH CURDEPTH
顯示隊列管理器的所有屬性
DISPLAY QMGR [ALL]
顯示進程定義
DISPLAY PROCESS(PRONAME)
更改屬性
ALTER QMGR DESCR(‘NEW DESCRIPTION’)
ALTER QLOCAL(QNAME) PUT(DISABLED)
ALTER QALIAS(QNAME) TARGQ(TARGQNAME)
刪除隊列
DELETE QLOCAL(QNAME)
DELETE QREMOTE(QRNAME)
清除隊列中的所有消息
CLEAR QLOCAL(QNAME)
以下是一些高級配置的命令:
amqmcert 配置SSL證書
amqmdain 配置windows上的MQ服務
crtmqcvx 轉換數據
dmpmqaut 轉儲對象權限管理
dmpmqlog 轉儲日志管理
dspmq 顯示隊列管理器
dspmqaut 顯示打開對象的權限
dmpmqcap 顯示處理程序容量和處理程序數
dspmqcsv 顯示命令服務器狀態
dspmqfls 顯示文件名
dspmqtrc 跟蹤MQ輸出(HP-UNIX LINUX Solaris)
dspmqrtn 顯示事務的詳細信息
endmqcsv 停止隊列管理器上的命令服務器
strmqcsv 啟動隊列管理器上的命令服務器
endmqtrc 停止跟蹤
rcdmqimg 向日志寫對象的映像
rcmqobj 根據日志中的映像重新創建一個對象
rsvmqtrn 提交或逆序恢復事務