2016年1月24日 星期日

Lex與正則表示式練習

               
LEX是用來製作scanner/Lexer等工具的工具在編譯器領域常常會用到,使用LEX可以將輸入的文字資料過濾成一個個有意義的單元(token),當然這一些token由使用者自己決定。

LEX使用正則表示式來描述一個token的長相
常看網路上的高手說學會用正則表示式才算是邁向職業的程式設計師,所以趕緊來學一學。

正則表示式並不是LEX獨有正則表示式在很多程式語言都可以看到它的存在,比如神級的語言 : perl

正則表示式其實是一種科學的概念,起源於grep/sed等工具中,主要用來做字串比對,例如”  搜尋與取代”這種操作。

以下列了一些LEX正則表示式的簡單操作。

LEX基本格式如下圖,其中最重要的就是中間由2個%%包覆的規則區塊,由成對的pattern與action組成,當輸入的來源符合某個pattern時,就會去執行該pattern所對應的action。而正則表示式的功用就是可以很細膩的去描述每ㄧ個pattern。


以下是一些範例與執行結果

.    小數點

可以代表任何字元或數字,除了\n(換行)以外
例如:
        %%
.    { printf("pattern Dot ") ; }
        %%


[ ]    方括號

1.   在方括號[ ]中可以表示一串字元組的其中一個字元:
      例如:
                [123]     { printf("pattern [123] ") ; }
                上式代表若輸入是1 2 3其中一個,就執行printf

2.  可用 ‘-’符號表示某一個範圍(Range)字元 :
      例如:
                [1-9] { printf("pattern [1-9] ") ; }
               上式等同於[0123456789]

3.  若方括號的第一個字元為 ‘^’,代表反向
     例如:
               [^1-9] { printf("pattern [^1-9] ") ; } ,
        上式代表除了1到9之外的字元都符合條件

範例如下:
/*
   [\n\t ]   遇到空白與換行, 直接換行
   pattern1= [123] , pattern2 = [1-9] , pattern3 = [^1-9]
*/
%%
       [\n\t ]         {printf("\n");}
       [123]         { printf("pattern [123] ") ; }
       [1-9]         { printf("pattern [1-9] ") ; }
       [^1-9]         { printf("pattern [^1-9] ") ; }
%%
如下圖的結果,只有輸入1 ,2, 3才會被pattern 1匹配且可輸入多
次,輸入4的話就會跑到pattern 2去了,若輸入字母會執行pattern3



^    尖號
   
^ 代表一個表示式的起頭,但是若用在方括號裡面的開頭,則代表向條件。
例如:
^abcdefg       { printf("pattern letter ") ; }
[ ^abcdefg ]        { printf("pattern reverse ") ; }

$    錢字號

用來代表一個式子的結尾,放在表示式的最後面
例如:
    abcedfg$    { printf("pattern letter ") ; }

\    脫逸字元

字元 \’加在任何符號前面會讓原本有意義的字元失去功能,變成只是
單純的字元而已 。
例如:
%%
\.    { printf("pattern escape ") ; }
%%
原本'.'可以代表任何字元,但經過'\'修飾後,變成只是 '.' 這個字 。
輸入數字或字母都不會匹配,只有輸入'.' 才會執行動作 。


*     星號

在星號的前一個式子或字元(包含空白)可以被重複零次(不出現)或多次 。
例如:
[ ]*
[1-9]*

+    加號

在加號的前一個式子或字元(不包含空白)至少要出現1次以上,或多次 。
例如:
[0-9]


範例:浮點數表式
%%
[0-9 ]*\.[0-9]+     { printf("floating-point ") ; }
%%
表示式結果如下, 在小數點前面可以不出現,但後面至少要出現一次
才會執行動作 。

|   

如一般的程式語言一樣,可以將多個表示式做或|操作 。
例如:
  %%
        iphone-[1-6]+|HTC-M[7-8]+|Sony-Z[1-5]+    {printf("smart phone") ;}
   %%
當輸入其中一個字串時就執行動作。
    ps :  |’ 出現在中括號裡面就會失去功能,變成一般的字元。

{ }    大括號

大括號在當作pattern用的時候有2種不同的含義
1. 做為別名(簡稱),可以代表任何一個表示式 。
    例如:
                      letter     [ a-z]
2. 指定表示式repeat(重覆)的次數 。
例如:
        /* X要重複3= XXX ,才會執行動作 。 */
X{3}     { printf("pattern repeat ") ; }


範例如下:   
number    [0-9]+
Name        "Joe"
Age           "17-years"
%%
{number}      {printf("pattern Number ") ;}
{Name}{3}     {printf("pattern Name ") ;}
{Age}{1,3}      {printf("pattern Age ") ;}
%%


?     問號

若有一個式子或字元出現在問號前面,代表該式子可以出現一次
或者完全沒有出現。
例如 ,判斷輸入網址的格式:
    %%
          "http://"?"www"\.[a-z]+\.[a-z]+\.[a-z]+    { printf(" IP address ") ;}
    %%
執行結果如下,不管有沒有加上"http://"都符合條件。


()    小括號

就可以將多個式子用小括號()包起來,這樣就會變成一個新的表示式。
例如 :
%%
         ([a-z]+|[A-Z]+)|([0-9]+|([0-9]*\.[0-9]+))    {printf("letter and int") ;}
%%