2011-03-27 1449 views
7

給定一個文本文件,我想匹配的字符用單引號分隔,但可能有零個或一個轉義的單引號,報價,以及零個或多個製表符和換行符(不轉義) - 我只想匹配文本。例如:Python正則表達式匹配單引號中的文本,忽略轉義引號(和製表符/換行符)

menu_item = 'casserole'; 
menu_item = 'meat 
      loaf'; 
menu_item = 'Tony\'s magic pizza'; 
menu_item = 'hamburger'; 
menu_item = 'Dave\'s famous pizza'; 
menu_item = 'Dave\'s lesser-known 
    gyro'; 

我要搶只有文本(和空格),忽略標籤/換行 - 我並不真正關心,如果逃跑報價出現在結果,只要它不影響比賽:

casserole 
meat loaf 
Tonys magic pizza 
hamburger 
Daves famous pizza 
Dave\'s lesser-known gyro # quote is okay if necessary. 

我必須設法創造一個正則表達式是幾乎做它 - 它處理的轉義引號,而不是新行:

menuPat = r"menu_item = \'(.*)(\\\')?(\t|\n)*(.*)\'" 
for line in inFP.readlines(): 
    m = re.search(menuPat, line) 
    if m is not None: 
     print m.group() 

那裏肯定有很多正則表達式的問題 - 但大多數都使用Perl,如果有一個能夠做到我想要的,我無法弄清楚:)因爲我使用的是Python,所以我沒有注意它是否分佈在多個組中,很容易重新組合。

一些答案已經說過,只是用代碼解析文本。雖然我確信我可以做到這一點 - 我很關閉有一個工作正則表達式:)而且它似乎是應該是可行的。

更新:我剛剛意識到我正在做一個Python readlines()來獲得每一行,這顯然是分裂線傳遞給正則表達式。我正在考慮重新編寫它,但任何有關該部分的建議也會非常有幫助。

+0

可能重複的,用於管理轉義字符項目像字符串文字](http://stackoverflow.com/questions/430759/regex-for-managing-escaped-characters-for-items-like-string-literals) – phooji 2011-03-27 22:28:45

+0

不是重複 - 我試圖處理(非轉義的)換行符也打破了我的輸入數據。 – 2011-03-27 22:30:52

+1

我同意,但我認爲無論如何都值得指出。只需使用're.MULTILINE'(http://docs.python.org/library/re.html#re.MULTILINE)匹配多行,'$'忽略/匹配endlines和'\ s'(相同的鏈接)匹配新聞空間。出來,蚱蜢;) – phooji 2011-03-27 22:47:44

回答

3

這應做到:

menu_item = '((?:[^'\\]|\\')*)' 

這裏(?:[^'\\]|\\')*部分除了'\或文字\'任何性質的任何序列匹配。前面的表達式[^'\\]也允許換行符和製表符,然後您需要用一個空格來替換。

+0

當你說,「用一個空格替換」 - 你的意思是在運行這個RE之前清理/刪除標籤/換行符*?當我嘗試使用RE時,它不符合任何有斷點的行。 – 2011-03-27 22:00:18

+0

@John C:不,我會在之後用're.sub(r「[\ n \ r \ t] +」,「」,match)''來做。 – Gumbo 2011-03-27 22:03:45

+0

但是,我的匹配變量* m *對於有換行符的輸入行是空的,所以沒有什麼可以替代。 – 2011-03-27 22:05:23

1

你冷試試這樣說:

pattern = re.compile(r"menu_item = '(.*?)(?<!\\)'", re.DOTALL) 

它將開始在它找到的第一個單引號匹配,並在沒有反斜槓後面的第一個單引號結束。它還捕獲在兩個單引號之間找到的任何換行符和製表符。

+0

看起來很有意思,但正如我在另一條評論中指出的 - 我剛剛意識到我正在執行一個* readlines()*,它正在破壞新行,所以我還有另一個問題需要解決。 – 2011-03-27 22:28:02

12

該測試腳本應該做的伎倆:

import re 
re_sq_long = r""" 
    # Match single quoted string with escaped stuff. 
    '   # Opening literal quote 
    (   # $1: Capture string contents 
     [^'\\]* # Zero or more non-', non-backslash 
     (?:  # "unroll-the-loop"! 
     \\.  # Allow escaped anything. 
     [^'\\]* # Zero or more non-', non-backslash 
    )*   # Finish {(special normal*)*} construct. 
    )   # End $1: String contents. 
    '   # Closing literal quote 
    """ 
re_sq_short = r"'([^'\\]*(?:\\.[^'\\]*)*)'" 

data = r''' 
     menu_item = 'casserole'; 
     menu_item = 'meat 
        loaf'; 
     menu_item = 'Tony\'s magic pizza'; 
     menu_item = 'hamburger'; 
     menu_item = 'Dave\'s famous pizza'; 
     menu_item = 'Dave\'s lesser-known 
      gyro';''' 
matches = re.findall(re_sq_long, data, re.DOTALL | re.VERBOSE) 
menu_items = [] 
for match in matches: 
    match = re.sub('\s+', ' ', match) # Clean whitespace 
    match = re.sub(r'\\', '', match) # remove escapes 
    menu_items.append(match)   # Add to menu list 

print (menu_items) 

這裏是正則表達式的短版:

'([^'\\]*(?:\\.[^'\\]*)*)'

這正則表達式是使用優化的傑弗裏·弗裏德爾的「展開-the-循環「效率技術。 (詳見:Mastering Regular Expressions (3rd Edition))。

注意的是,上述正則表達式是等效於以下一個(其更常見,但是在大多數NFA regex實現慢得多):的[正則表達式

'((?:[^'\\]|\\.)*)'

相關問題