《電子技術(shù)應用》
您所在的位置:首頁 > 嵌入式技術(shù) > 設計應用 > 正則表達式在優(yōu)化計算中的應用
正則表達式在優(yōu)化計算中的應用
來源:微型機與應用2012年第12期
林 力, 馬 昕, 張貝克
(北京化工大學 信息科學與技術(shù)學院, 北京100029)
摘要: 在編寫優(yōu)化算法軟件時,用戶輸入的表達式通常是字符串類型,如何實現(xiàn)用戶與計算機的交互,即怎樣讓計算機讀懂用戶輸入的字符串類型的數(shù)學表達式,是計算機優(yōu)化計算所要面臨的首要問題。在VS中調(diào)用DEELX正則語言庫,采用匹配、替換的方法實現(xiàn)對用戶輸入函數(shù)表達式的判別、計算,并在實現(xiàn)計算表達式的基礎上計算表達式導數(shù)和求解極值。
Abstract:
Key words :

摘  要: 在編寫優(yōu)化算法軟件時,用戶輸入的表達式通常是字符串類型,如何實現(xiàn)用戶與計算機的交互,即怎樣讓計算機讀懂用戶輸入的字符串類型的數(shù)學表達式,是計算機優(yōu)化計算所要面臨的首要問題。在VS中調(diào)用DEELX正則語言庫,采用匹配、替換的方法實現(xiàn)對用戶輸入函數(shù)表達式的判別、計算,并在實現(xiàn)計算表達式的基礎上計算表達式導數(shù)和求解極值。
關(guān)鍵詞: 正則表達式優(yōu)化算法軟件; DEELX

    傳統(tǒng)的優(yōu)化程序一般都是針對某個具體的待優(yōu)化問題進行編寫的,缺乏通用性,用戶還需要花費一段時間來學習如何使用軟件。優(yōu)化軟件若具有良好的交互性,用戶只需要輸入目標函數(shù)、約束條件、自變量、初始點就可以求得最優(yōu)解和此時的函數(shù)值。要實現(xiàn)對用戶輸入問題的求解,首先面對的問題就是如何讓計算機讀懂用戶所輸入的待求解問題。由于用戶所輸入的目標函數(shù)、約束條件、自變量都是字符串類型的,所以要通過對字符串進行處理來實現(xiàn)計算機對函數(shù)表達式的理解。而正則表達式通常用檢索和替換那些符合某個模式的文本內(nèi)容,本文采用正則表達式進行字符串的匹配、替換來實現(xiàn)計算機對用戶輸入表達式的讀入[1-2]。
1 優(yōu)化程序結(jié)構(gòu)
    用戶通過一個問題輸入對話框與計算機進行交互,在對話框中用戶需要輸入待優(yōu)化問題的目標函數(shù),約束條件,計算精度等參數(shù),點擊求解按鈕進行運算。若用戶有非法輸入則提示用戶重新輸入,如果求解失敗則彈出求解失敗對話框。例如用戶需要求解問題min f (t,s)=0.5t2+s2/4,s.t ts=1,則需要在目標函數(shù)欄輸入0.5*t^2+s^2/4,在約束條件欄輸入t*s-1=0。
     程序主要由COptimize、CFunctionCaluclate、CNumericalCaluclate三個類構(gòu)成。CFunctionCaluclate用于實現(xiàn)對用戶輸入表達式的校驗,將表達式中的變量替換為數(shù)值并計算結(jié)果,獲取表達式在指定點的一、二階導數(shù)等功能。CNumericalCalculation用于實現(xiàn)對替換后只包含數(shù)字項的表達式進行基礎運算,包括基本的四則運算以及冪函數(shù)運算。COptimize通過實例化CFunctionCaluclate,在實現(xiàn)表達式求值、求導的基礎上完成對用戶輸入函數(shù)的求解極值。在交互界面上,用戶需要輸入函數(shù)表達式,以及表達式中所包含的變量和變量的初始值大小。程序的對象模型如圖1所示。

2 正則表達式運用于函數(shù)表達式的計算
 正則表達式在很多文本編輯器或其他工具里,用來檢索和替換符合某個模式的文本內(nèi)容,目前許多程序設計語言都支持利用正則表達式進行字符串操作[3]。由于用戶輸入的目標函數(shù)和約束條件都是字符串類型的,所以正則表達式可以應用于函數(shù)表達式的計算。
     DEELX 是一個在C++環(huán)境下的正則表達式引擎[4],全部采用模板 template 編寫,可將 DEELX 用于char、 wchar_t 以及其他基類型,比如unsigned char、int等。但只能是簡單數(shù)據(jù)類型,不可以是 struct 或者 union 等復合類型。DEELX全部代碼位于一個頭文件(deelx.h)中,使用時只需要簡單地添加一個 #include"deelx.h"就可以了。
    在本文中,采用匹配、替換的方法實現(xiàn)對用戶輸入函數(shù)表達式的判別、計算。首先,用給定初始點的值對自變量進行替換,將函數(shù)表達式變?yōu)橹缓袛?shù)字項的數(shù)學表達式,再通過正則語言的匹配將數(shù)學表達式劃分為各個子運算塊,然后將計算結(jié)果代替原表達式中的子運算塊,如此循環(huán),直到最后只剩下一個數(shù)字,即為計算結(jié)果。
2.1 自變量的替換
     在CFunctionCaluclate中添加兩個公有函數(shù)Capture_Variables( ):void和Capture_GivenPoints( ):void,分別用來獲取自變量和給定值,并將捕獲到的自變量和給定值分別放入兩個vector<const char*>類型的成員變量m_vecVariables和m_vecValues中。
    首先將儲存自變量的m_vecVariables中的元素作為正則表達式,將其進行匹配并替換為相應的給定值,這時函數(shù)表達式已變成只含有數(shù)字項的數(shù)學表達式。變量替換的流程圖如圖2所示。
2.2 只含數(shù)字項表達式的計算
   CNumericalCalculation用來對替換后只包含數(shù)字項的函數(shù)表達式進行運算,包括基本的四則運算以及冪函數(shù)運算。在CFunctionCaluclate中通過實例化一個CNumericalCalculation的對象m_Calcution來調(diào)用它的計算函數(shù)。按照運算的優(yōu)先級,調(diào)用的順序依次為冪函數(shù)運算、乘除函數(shù)運算、加減函數(shù)運算。
    CNumericalCalculation類中有私有函數(shù)CString Genral_Calculation( CString expression, MODEL calculation_model ),Genral_Calculation( ) 的程序流圖如圖3所示。

 

 

    在CNumericalCalculation中已經(jīng)定義了針對不同函數(shù)計算的正則表達式,Power、Multi_Divid、Plus、Minus是在Genral_Calculation( )中枚舉的類型為 MODEL的變量,通過不同的MODEL類型來確定采用哪種計算類型,并選取其對應的正則表達式來匹配子運算塊。
    通過公共函數(shù)CString My_pow(CString fun_expression)、
CString My_multi_divid(CString fun_expression)、CString My_
plus_minus( CString fun_expression)來實現(xiàn)基本的冪函數(shù)、乘除、加減計算,并為CNumericalCalculation提供外部接口。
    例如,My_pow( ) 實現(xiàn)對冪函數(shù)的計算,它的實現(xiàn)代碼為:
    CString CNumericalCalculate::My_pow(CString fun_expression)
      {
        fun_expression = \
        Genral_Calculation(fun_expression,Power);
        return fun_expression;
  }
    My_pow( )被傳進來的參數(shù) fun_expression為只含數(shù)字項的表達式,在Genral_Calculation( )中通過參數(shù)Power來確定為冪函數(shù)計算。
   My_multi_divid ( ) 實現(xiàn)對乘除函數(shù)的計算,它的實現(xiàn)代碼與冪函數(shù)一樣,只是在調(diào)用Genral_Calculation( )時確定計算類型的參數(shù)為Multi_Divid。
    My_plus_minus( ) 實現(xiàn)對加減函數(shù)的計算,在調(diào)用Genral_Calculation( )前要對此時的表達式進行符號的合并,原因是由于加減運算的優(yōu)先級別最低,在進行加減運算時表達式只包含“+”、“-”兩種符號,所以需要進行符號的合并。Sign_Combination( )用來對表達式中的符號進行合并,將“++”、“--”合并為“+”,“+-”、“-+”合并為“-”。
2.3 運算優(yōu)先級問題
    為了實現(xiàn)乘除運算從左至右的順序,必須先進行除法運算,否則會產(chǎn)生錯誤,例如:
    4/2*2,從左至右的運算順序會得到4,若先進行乘運算,則變成4/(2*2),此時得到的結(jié)果為1。這是因為在運算過程中,被“/”所連接的兩個數(shù)字應該被看作是一個分數(shù)整體,先做除法只是求出了分數(shù)的有理型式,所以先進行除法運算不會改變運算結(jié)果。
    這里將乘除法合并在一起,在從左至右的匹配過程中,匹配到乘函數(shù)就用乘法運算,遇到除函數(shù)就用除法運算,這樣就實現(xiàn)了從左至右的運算順序。
    若將乘除法運算分開,先做所有的除法運算,再做所有的乘法運算也會得到正確的結(jié)果,但這為程序調(diào)試添加了潛在的危險,若不小心顛倒乘除運算順序,這個錯誤將會很難發(fā)現(xiàn)。
2.4 匹配子算式的正則表達式
    上文說明了程序計算函數(shù)表達式的原理及大致的實現(xiàn)方法,但如何實現(xiàn)對不同的運算法則進行匹配,是使用正則表達式最復雜的地方。
    由于在用初始點替換變量之后會出現(xiàn)“+-”、“++”、“- -”等符號,所以簡單的正則表達式不能實現(xiàn)完全正確的匹配。例如:
    -X1^2 +X2-X3-X4,若此時X1=2,X2=-3,X3=4,X4=-5,那么此時的表達式為:
    -2^2+-3-4--5,用簡單的匹配表達式“[+-]\d+\.?\d*”來匹配,用括號表示被匹配項,那么被捕獲到的數(shù)字項為(-2)^(2)+(-3)(-4)-(-5),很明顯,捕獲結(jié)果有錯,首先第一項是-(2)^(2),前面的符號也進行了冪運算;還有第三項(-4),運算符號被捕獲為負號。顯然,這種簡單的匹配表達式還會帶來更多的錯誤匹配。
    在本文中,先對用戶輸入的初始點進行判斷,若是負數(shù)則直接替換變量,若是正數(shù),則在數(shù)字前添加“+” ,這樣就能解決表達式首變量前面為負號的情況,例如此時給2添加“+”號,就能獲得正確的捕獲結(jié)果-(+2)^(2)。
     先使用如下正則表達式來匹配數(shù)字項:
    (?<=[\^\-+*/])[+\-]\d+\.?\d*|^[+-]\d+\.?\d*|\d+\.?\d*
     這是由三個匹配規(guī)則用分枝條件組成的正則表達式。
    (?<=[\^\-+*/])[+\-]\d+\.?\d*來捕獲運算符號后面帶正負號的數(shù)字,如“-2^2+-3-4--5”中的“-3”“-5”;
    ^[+-]\d+\.?\d*來捕獲表達式開頭帶正負號的數(shù)字,
如“ –2^2 + -3-4--5”中的“-2”;
     \d+\.?\d*來捕獲表達式中不帶正號的正數(shù),如“-2^2 + -3-4--5”中的“2”。
    通過正則表達式的簡化,前兩種匹配規(guī)則合并后得到:
     ((?<=[\^\-+*/]|^)[+\-]\d+\.?\d*)|(\d+\.?\d*)
     再次合并兩種規(guī)則得到:
     ((?<=[\^\-+*/]|^)[+\-])?\d+\.?\d*
     對于以空格開頭的數(shù)字,加上\s進行匹配,最終匹配數(shù)字的正則表達式為:
     ((?<=[\^\s\-+*/]|^)[+\-])?\d+\.?\d*
     在實現(xiàn)了數(shù)字項的匹配后,可以很容易地獲取匹配冪函數(shù)的正則表達式,即在兩個數(shù)字中間插入冪函數(shù)計算符號:
    (((?<=[\^\s\-+*/]|^)[+\-])?\d+\.?\d*)\s*\^\s*(?1)
    匹配乘除、加減函數(shù)的正則表達式與冪函數(shù)相似,都是在數(shù)字項之間加入運算符號來匹配子算式。
2.5 對含有括號項的處理
    匹配括號項的正則表達式為:\([^()]*\)。
     其含義為以“(”開頭,“)”結(jié)尾且不包含“( )”項的字符串。對含有括號的表達式,先匹配括號內(nèi)的表達式,并調(diào)用Calculate( )函數(shù)來計算其結(jié)果,再用計算結(jié)果來代替所匹配到的括號項。如此循環(huán),直到括號項不存在。然后計算無括號的表達式,得到最終的計算結(jié)果。
3 正則表達式用于表達式的錯誤檢查
    用戶在輸入表達式時,難免會輸入一些錯誤的數(shù)學表達式,比如在數(shù)字中出現(xiàn)多個小數(shù)點、括號的錯誤使用、變量個數(shù)與給定的初始值個數(shù)不符、初始值非純數(shù)字、所給變量與函數(shù)表達式中的不符等,都可以通過建立相關(guān)的正則表達式來進行錯誤匹配,當匹配成功后就提示用戶輸入錯誤,幫助用戶輸入正確的表達式與參數(shù)。
    CFunctionCaluclate中的Error_Identify( )用來檢測用戶輸入的函數(shù)表達式、自變量、給定值是否含有錯誤。
     通常與小數(shù)點相關(guān)的錯誤是數(shù)字項中含有多個小數(shù)點,如“2..5”和“2.3.4”都是非法輸入,通過正則表達式來匹配數(shù)字項中的多個小數(shù)點,若匹配成功,則說明存在小數(shù)點非法輸入。
     括號的非法使用通常包含兩種情況,一是函數(shù)表達式開頭有右括號或結(jié)尾有左括號,例如“a+)6*b-c”和“a-b^2+(c-d”都是第一種錯誤類型;二是左括號與右括號的數(shù)量不相等,即含有不完整的括號對,例如“a*(b-c*(2-d)”式中未能構(gòu)成一個完整的括號對。
    針對以上兩種錯誤類型,采用不同的判別方法。對于第一種錯誤類型,用正則表達式“^[^(]*\)|\([^)]*$”來匹配表達式開頭的“)”或結(jié)尾的“(”,若匹配成功,則說明函數(shù)表達式有非法的括號使用;對于第二種錯誤類型,先設置一個計數(shù)器并初始為零,若匹配到一個左括號則計數(shù)器加一,匹配到右括號計數(shù)器減一,如果最后計數(shù)器不為零,則說明左右括號數(shù)量不同,肯定含有不完整的括號對,表達式存在非法的括號使用。
    有關(guān)用戶輸入自變量的錯誤,第一種是自變量個數(shù)與對應的給定值個數(shù)不符,例如自變量有“a、b、c” ,而給定值為“1、2”或“1、2、3、4” ,都無法進行正確的替換,這種錯誤較為容易檢測,只要在獲取了自變量和給定值以后,比較兩個容器中的元素個數(shù),若不相等則說明自變量個數(shù)與對應的給定值個數(shù)不符。第二種是函數(shù)表達式中的變量,在自變量輸入欄用戶沒有給出相應的變量,例如函數(shù)表達式為“a*(b-c*(2-d))” ,而用戶只給出了“a、b、c”的給定值,“d”是一個未知變量,對于這種錯誤,要先對函數(shù)表達式進行自變量的捕獲,并將其放入一個vector中,再與用戶所給的自變量進行匹配,若有自變量沒能匹配成功,則說明含有未知的自變量,這時需要提示用戶輸入錯誤。
    通過在VS中使用正則表達式,成功地實現(xiàn)了對字符串類型的函數(shù)表達式的讀入,為用戶提供了良好的交互接口,用戶只需輸入目標函數(shù)、約束條件、自變量、初始點就可以求得最優(yōu)解和此時的函數(shù)值。并能對用戶的輸入進行檢查,在用戶輸入錯誤時給出提醒。
    同時,正則表達式的使用不僅僅針對優(yōu)化程序,其他程序在面對表達式的數(shù)值計算時,同樣會遇到如何理解用戶輸入字符串類型表達式的困難,本文中的方法可以用來解決此類問題。
    本文中所用方法的缺點是,使用正則表達式理解用戶輸入表達式,會隨著表達式的復雜度增加,運算時間也會隨之增長,在使用某些優(yōu)化算法時,需要計算比較復雜的算式,會使問題的規(guī)劃時間變得較長。
參考文獻
[1] 翟自洋,林昌東.利用正則表達式進行查找/替換[J].中國科技期刊研究,2009,20(1):122-126.
[2] 曹光琦.Boost.Regex_C++正則表達式快速入門[J]. 程序員,2004(04):78-81.
[3] 李旻,陳和平.正則表達式在數(shù)據(jù)庫查詢中的應用[J].計算機工程與設計,2006,27(12):2302-2305.
[4] DEELX正則引擎文檔[CP/OL].(2006-09-20)[2011-04-25].http://www.regexlab.com/zh/regref.htm,2006,9.[2011,4].

此內(nèi)容為AET網(wǎng)站原創(chuàng),未經(jīng)授權(quán)禁止轉(zhuǎn)載。
主站蜘蛛池模板: 国语对白自拍 | a色在线| 日本成人久久 | 亚洲精品福利网站 | 日韩欧美亚 | 中文字幕视频免费在线观看 | vktk视频| 成人深夜视频 | 亚洲噜噜噜噜噜影院在线播放 | 美国一级毛片a | 国产成人精品免费视频 | 无遮挡h纯内动漫在线观看 无遮挡1000部拍拍拍免费观看 | 91精品国产自产91精品 | 99久久亚洲 | 偷偷狠狠的日日高清完整视频 | 手机国产日韩高清免费看片 | 国产一级特黄高清免费大片 | 在线观看不卡视频 | 真正全免费视频a毛片 | 性欧美video超清 | 日本全黄 | 在线色av| 成人在线影视 | 欧美在线观看网址 | 欧美日韩国产在线一区 | 在线观看免费播放网址成人 | 成人看片黄a在线观看 | 欧美色图一区 | 97色伦图片在线观看 | 嫩草影院永久在线一二三四 | 理论毛片 | 国产专区在线 | 德国最新精品性hd | 日本簧片| 国产一区免费视频 | 91视频一区二区三区 | 久久成人免费网站 | 久久国产欧美日韩精品免费 | 久久6热 | 日韩中文字幕在线免费观看 | 日韩亚洲欧美一区 |