正则表达式匹配引号组合之间的任何内容

时间:2016-06-30 18:56:44

标签: python regex python-3.x quotes

[从我原来的question跟进,提供更好的说明和链接]

尝试匹配两个符号之间的任何字符(包括换行符,制表符,空格等)。

例如:

  

foobar89 \ n \ nfoo \ TBAR; '' blah blah blah' 8& ^"''''

需要匹配

  

'' blah blah blah' 8& ^"'''

  

fjfdaslfdj; '' blah \ n blah \ n \ t \ t blah \ n' 8& ^"'''

需要匹配

  

'' blah \ n blah \ n \ t \ t blah \ n' 8& ^"''''

我正在测试正则表达式的我的Python代码(从here获取和改编):

import collections
import re

Token = collections.namedtuple('Token', ['typ', 'value', 'line', 'column'])

def tokenize(code):
    token_specification = [
        ('BOTH',      r'([\'"]{3}).*?\2'), # for both triple-single quotes and triple-double quotes
        ('SINGLE',    r"('''.*?''')"),     # triple-single quotes 
        ('DOUBLE',    r'(""".*?""")'),     # triple-double quotes 
        # regexes which match OK
        ('COM',       r'#.*'),
        ('NEWLINE', r'\n'),           # Line endings
        ('SKIP',    r'[ \t]+'),       # Skip over spaces and tabs
        ('MISMATCH',r'.'),            # Any other character
    ]

    test_regexes = ['COM', 'BOTH', 'SINGLE', 'DOUBLE']

    tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
    line_num = 1
    line_start = 0
    for mo in re.finditer(tok_regex, code):
        kind = mo.lastgroup
        value = mo.group(kind)
        if kind == 'NEWLINE':
            line_start = mo.end()
            line_num += 1
        elif kind == 'SKIP':
            pass
        elif kind == 'MISMATCH':
            pass
        else:
            if kind in test_regexes:
                print(kind, value)
            column = mo.start() - line_start
            yield Token(kind, value, line_num, column)

f = r'C:\path_to_python_file_with_examples_to_match'

with open(f) as sfile:
    content = sfile.read()

for t in tokenize(content):
    pass #print(t)

file_with_examples_to_match所在的位置:

import csv, urllib

class Q():
    """
    This class holds lhghdhdf hgh dhghd hdfh ghd fh.
    """

    def __init__(self, l, lo, d, m):
        self.l= l
        self.lo= longitude
        self.depth = d
        self.m= m

    def __str__(self):
        # sdasda fad fhs ghf dfh
        d= self.d
        if d== -1:
            d= 'unknown'
        m= self.m
        if m== -1:
            d= 'unknown'

        return (m, d, self.l, self.lo)

foobar89foobar; '''blah qsdkfjqsv,;sv
                   vqùlvnqùv 
                   dqvnq
                   vq
                   v

blah blah'8&^"'''
fjfdaslfdj; '''blah blah
     blah
    '8&^"'''

this answer开始,我尝试r"('''.*?''')|"r'(""".*?""")来匹配三重单引号和三重双引号的情况,但没有成功。尝试r'([\'"]{3}).*?\2')时也一样。

我已经设置了一个online正则表达式测试程序,其中一些正则表达式符合预期,但在上面的代码中它们会失败。

我有兴趣了解Python的正则表达式,所以我很感激一个解决方案(可能是一个有效的正则表达式来对我的代码进行所需的匹配)和一个简短的解释,所以我可以看到我的缺点。 / p>

1 个答案:

答案 0 :(得分:1)

你可能错过了让.匹配换行符的标志

re.finditer(tok_regex, code, flags = re.DOTALL)

在这种情况下输出为

('BOTH', '"""\n    This class holds lhghdhdf hgh dhghd hdfh ghd fh.\n    """')
('COM', '# sdasda fad fhs ghf dfh\n        d= self.d\n        if d== -1:\n            d= \'unknown\'\n        m= self.m\n        if m== -1:\n            d= \'unknown\'\n\n        return (m, d, self.l, self.lo)\n\nfoobar89foobar; \'\'\'blah qsdkfjqsv,;sv\n                   vq\xc3\xb9lvnq\xc3\xb9v \n                   dqvnq\n                   vq\n                   v\n\nblah blah\'8&^"\'\'\'\nfjfdaslfdj; \'\'\'blah blah\n     blah\n    \'8&^"\'\'\'')

COM现在匹配太多,因为.现在将所有内容都放到文件末尾。如果我们稍微修改这个模式以减少贪心

('COM',       r'#.*?$')

我们现在可以使用re.MULTILINE使其匹配更少

re.finditer(tok_regex, code, flags = re.DOTALL | re.MULTILINE)

现在的输出是

('BOTH', '"""\n    This class holds lhghdhdf hgh dhghd hdfh ghd fh.\n    """')
('COM', '# sdasda fad fhs ghf dfh')
('BOTH', '\'\'\'blah qsdkfjqsv,;sv\n                   vq\xc3\xb9lvnq\xc3\xb9v \n                   dqvnq\n                   vq\n                   v\n\nblah blah\'8&^"\'\'\'')
('BOTH', '\'\'\'blah blah\n     blah\n    \'8&^"\'\'\'')

如果你绝对不想使用旗帜,你可以使用一种&#39; hack&#39;没有.,因为除了换行符之外,这个元字符几乎可以匹配所有内容。您可以创建一个匹配组,该匹配组将匹配除一个符号之外的所有内容,这很可能不会出现在您要解析的文件中。例如,您可以使用带有ASCII代码0的字符。此类字符的正则表达式为\x00,相应的模式[^\x00]将匹配每个符号(甚至是换行符),但ASCII码为0的符号除外(这就是为什么它是一个黑客,你不能没有标志匹配每个符号)。您需要为COM保留初始正则表达式,对于BOTH,它将是

('BOTH',      r'([\'"]{3})[^\x00]*?\2')

强烈推荐使用正则表达式的是可以解释它们的在线工具,例如regex101

对于更复杂的引用匹配案例,您需要编写解析器。例如,请参阅此Can the csv format be defined by a regex?和此When you should NOT use Regular Expressions?