【问题标题】:RegEx for extracting placeholder matches用于提取占位符匹配的 RegEx
【发布时间】:2019-10-14 07:47:54
【问题描述】:

我有这个字符串

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

我想测试我的字符串是否与该模板匹配,并且任何东西都可以代替占位符。占位符以 &lt;place holder here&gt; 这样的括号开始和结束。例如这个字符串会匹配

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

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

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

我可以使用模式&lt;(.*?)&gt; 为正则表达式提取模板的占位符,但我目前仍坚持如何从字符串中提取实际替换。我需要一个通用的方法,我不想硬编码模式以匹配完整的模板,因为我有很多模板要检查。有没有聪明的方法来做到这一点?

【问题讨论】:

    标签: python regex regex-lookarounds regex-group


    【解决方案1】:

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

    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)
    

    将此与交叉引用模板中的占位符结合起来,您就有更多的命名选项。

    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'}
    

    【讨论】:

    • 这是我第一次使用 Python。如果您发现新手代码/优化,请告诉我。
    • "&lt;[^&gt;]+&gt;" 更改为 "&lt;[^&gt;]*&gt;" 以允许空占位符。
    • 这正是我所需要的。谢谢:D
    【解决方案2】:

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

    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.
    

    【讨论】:

    • 谢谢,但不是我想要的。我想要一个更通用的方法。基本上我想创建一个函数func,如果我调用func(template, string),它会返回['John Doe', '30 years old']func 也应该适用于其他模板。标点不重要。占位符(带有一对括号&lt;&gt;)可以。
    猜你喜欢
    • 2019-03-14
    • 2018-02-02
    • 1970-01-01
    • 1970-01-01
    • 2020-11-13
    • 1970-01-01
    • 1970-01-01
    • 2019-04-08
    • 2011-09-13
    相关资源
    最近更新 更多