5

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

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 正则表达式上发布的答案中的解决方案来匹配单引号中的文本,忽略转义引号(和制表符/换行符)无济于事。

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

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

4

2 回答 2

5

我认为 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
于 2012-11-05T22:06:52.443 回答
5

编辑

我的初始正则表达式解决方案中有一个错误。该错误掩盖了您输入字符串中的错误: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')]
于 2012-11-05T20:57:54.377 回答