2011-03-27 55 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实现慢得多):的[正则表达式

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

相关问题