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

Regular expression to match anything between combination of quotes

[从我的旧 跟进,提供更好的描述和链接]

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

例如:

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}).*?'), # 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&^"'''

开始,我尝试 r"('''.*?''')|"r'(""".*?""") 匹配三重单引号和三重双引号,但均未成功。尝试 r'([\'"]{3}).*?').

时相同

我已经设置了一个 online 正则表达式测试器,其中一些正则表达式确实匹配,但在上面的代码中它们失败了。

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

您可能缺少使 . 也匹配换行符的标志

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&^"\'\'\'')

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

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

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

对于更复杂的引号匹配情况,您需要编写解析器。例如,参见 Can the csv format be defined by a regex? and this When you should NOT use Regular Expressions?.