【问题标题】:Parsing single or double quotes and allow for escaped characters using regular expressions (in Python)解析单引号或双引号并允许使用正则表达式转义字符(在 Python 中)
【发布时间】:2012-10-25 18:16:55
【问题描述】:

我的输入看起来像一个参数列表:

input1 = '''
title="My First Blog" author='John Doe'
'''

值可以用单引号或双引号括起来,但是也允许转义:

input2 = '''
title='John\'s First Blog' author="John Doe"
'''

有没有办法使用正则表达式来提取单引号或双引号以及转义引号的键值对?

使用python,我可以使用以下正则表达式并处理非转义引号:

rex = r"(\w+)\=(?P<quote>['\"])(.*?)(?P=quote)"

然后返回:

import re
re.findall(rex, input1)
[('title', '"', 'My First Blog'), ('author', "'", 'John Doe')]

import re
re.findall(rex, input2)
[('title', "'", 'John'), ('author', '"', 'John Doe')]

后者不正确。我不知道如何处理转义的引号——假设在 (.*?) 部分。我一直在使用Python regex to match text in single quotes, ignoring escaped quotes (and tabs/newlines) 上发布的答案中的解决方案,但无济于事。

从技术上讲,我不需要 findall 来返回引号字符——而只是键/值对——但这很容易处理。

任何帮助将不胜感激!谢谢!

【问题讨论】:

    标签: python regex parsing


    【解决方案1】:

    编辑

    我的初始正则表达式解决方案中有一个错误。该错误掩盖了您输入字符串中的错误:input2 不是您认为的那样:

    >>> input2 = '''
    ... title='John\'s First Blog' author="John Doe"
    ... '''
    >>> input2      # See - the apostrophe is not correctly escaped!
    '\ntitle=\'John\'s First Blog\' author="John Doe"\n'  
    

    您需要将input2 设为原始字符串(或使用双反斜杠):

    >>> input2 = r'''
    ... title='John\'s First Blog' author="John Doe"
    ... '''
    >>> input2
    '\ntitle=\'John\\\'s First Blog\' author="John Doe"\n'
    

    现在您可以使用正确处理转义引号的正则表达式:

    >>> rex = re.compile(
        r"""(\w+)# Match an identifier (group 1)
        =        # Match =
        (['"])   # Match an opening quote (group 2)
        (        # Match and capture into group 3:
         (?:     # the following regex:
          \\.    # Either an escaped character
         |       # or
          (?!\2) # (as long as we're not right at the matching quote)
          .      # any other character.
         )*      # Repeat as needed
        )        # End of capturing group
        \2       # Match the corresponding closing quote.""", 
        re.DOTALL | re.VERBOSE)
    >>> rex.findall(input2)
    [('title', "'", "John\\'s First Blog"), ('author', '"', 'John Doe')]
    

    【讨论】:

    • 您能解释一下“或任何其他角色”部分吗?在or 中没有. 会使其始终匹配吗?
    • @LevLevitsky:点匹配任何字符,是的。但是之前的前瞻断言(?!\2) 确保它不是结束引号,因此实际上该点将匹配除结束引号之外的任何字符。
    • @LevLevitsky:但你说的完全正确,我的正则表达式有一个重大错误。现在修复它(交替的范围不正确)。谢谢你指点我!
    • 这点我不敢恭维,真的 :) 我还没想好你的正则表达式。不知何故,当它们冗长时,我似乎需要更长的时间......
    • @LevLevitsky:我更正的正则表达式突然给出了错误的结果。困惑的是,我仔细查看了输入字符串,发现最初的问题是 Jeff 没有使用原始字符串 - 请参阅我修改后的答案...
    【解决方案2】:

    我认为 Tim 对反向引用的使用使表达式过于复杂,并且(在这里猜测)也使它变慢。标准方法(在 owl book 中使用)是分别匹配单引号和双引号字符串:

    rx = r'''(?x)
        (\w+) = (
            ' (?: \\. | [^'] )* '
            |
            " (?: \\. | [^"] )* "
            |
            [^'"\s]+
        )
    '''
    

    添加一点后处理就可以了:

    input2 = r'''
    title='John\'s First Blog' author="John Doe"
    '''
    
    data = {k:v.strip("\"\'").decode('string-escape') for k, v in re.findall(rx, input2)}
    print data
    # {'author': 'John Doe', 'title': "John's First Blog"}
    

    作为奖励,这也匹配未引用的属性,例如 weight=150

    添加:这是一种没有正则表达式的更简洁的方法:

    input2 = r'''
    title='John\'s First Blog' author="John Doe"
    '''
    
    import shlex
    
    lex = shlex.shlex(input2, posix=True)
    lex.escapedquotes = '\"\''
    lex.whitespace = ' \n\t='
    for token in lex:
        print token
    
    # title
    # John's First Blog
    # author
    # John Doe
    

    【讨论】:

      猜你喜欢
      • 2011-05-01
      • 2013-05-10
      • 2010-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2012-11-24
      • 1970-01-01
      相关资源
      最近更新 更多