用于提取占位符匹配项的正则表达式

RegEx for extracting placeholder matches

我有这个字符串

template = "Hello my name is <name>, I'm <age>."

我想测试我的字符串是否与该模板匹配,以及是否可以用任何东西代替占位符。占位符以方括号开始和结束,如 <place holder here>。例如,此字符串将匹配

string = "Hello my name is John Doe, I'm 30 years old."

我还想提取替换占位符的部分字符串。对于上面的例子,我想得到列表:

['John Doe', '30 years old']

我可以使用正则表达式的模式 <(.*?)> 来提取模板的占位符,但我目前无法解决如何从字符串中提取实际替换的问题。我需要一种通用方法,并且我不想对模式进行硬编码以匹配完整模板,因为我有很多模板要检查。有什么巧妙的方法吗?

如果所需的输出后跟问题中提到的准确标点符号,我们可以简单地使用类似于以下的表达式:

is\s(.+?),|([0-9].+)\.

DEMO

测试

# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility

import re

regex = r"is\s(.+?),|([0-9].+)\."

test_str = "Hello my name is John Doe, I'm 30 years old."

matches = re.finditer(regex, test_str, re.MULTILINE)

for matchNum, match in enumerate(matches, start=1):

    print ("Match {matchNum} was found at {start}-{end}: {match}".format(matchNum = matchNum, start = match.start(), end = match.end(), match = match.group()))

    for groupNum in range(0, len(match.groups())):
        groupNum = groupNum + 1

        print ("Group {groupNum} found at {start}-{end}: {group}".format(groupNum = groupNum, start = match.start(groupNum), end = match.end(groupNum), group = match.group(groupNum)))

# Note: for Python 2.7 compatibility, use ur"" to prefix the regex and u"" to prefix the test string and substitution.

您可以使用模板动态构建正则表达式。然后将其与任何输入字符串进行匹配。

import re

template = "Hello my name is <name>, I'm <age>."
pattern = "^" + re.escape(template) + "$"
pattern = re.sub("<[^>]+>", "(?P\g<0>.*)", pattern)
regex = re.compile(pattern, re.DOTALL)

string = "Hello my name is John Doe, I'm 30 years old."
match = regex.match(string)

match.group(0)
#=> "Hello my name is John Doe, I'm 30 years old."
match.group("name")
#=> 'John Doe'
match.group("age")
#=> '30 years old'
match.groups()
#=> ('John Doe', '30 years old')

对模板的唯一限制是应使用有效的正则表达式组名称。

您可以通过简单地不使用命名的正则表达式组来解决这个问题。

# replacing
pattern = re.sub("<[^>]+>", "(?P\g<0>.*)", pattern)
# with
pattern = re.sub("<[^>]+>", "(.*)", pattern)

将此与模板中的 cross-referencing 占位符结合使用,您将有更多的命名选项。

placeholders = re.findall("<[^>]+>", template)
placeholders = list(map(lambda match: match[1:-1], placeholders))

dict(zip(placeholders, match.groups()))
#=> {'name': 'John Doe', 'age': '30 years old'}