字符串

时间:2017-12-29 20:04:37

标签: python regex python-3.x

我需要在字符串中的任何位置匹配以下内容之一:

${aa:bb[99]}
${aa:bb}
${aa}

但不是:

$${aa:bb[99]}
$${aa:bb}
$${aa}

我的python 3正则表达式是:

pattern = **r"[^\$|/^]**\$\{(?P<section>[a-zA-Z]+?\:)?(?P<key>[a-zA-Z]+?)(?P<value>\[[0-9]+\])?\}"

我正在寻找的是说不是$或字符串开头的正确方法。块r"[^\$|/^]"将正确检测所有情况,但如果我的字符串从第一个字符开始,则会失败。

我特里,没有成功:

r"[^\$|\b]... 
r"[^\$|\B]...
r"[^\$]...
r"[^\$|^] 

有什么建议吗?

3 个答案:

答案 0 :(得分:8)

使用否定的lookbehind:

(?<!\$)

然后按照您真正想要匹配的内容进行操作。这样可以确保您实际想要匹配的内容前面没有$(即\$之前没有匹配):

(?<!\$)\$\{(?P<section>[a-zA-Z]+?\:)?(?P<key>[a-zA-Z]+?)(?P<value>\[[0-9]+\])?\}
     ^  ^
     |  |
     |  +--- The dollar sign you actually want to match
     |
     +--- The possible second preceding dollar sign you want to exclude
  

(?<!...)

     

匹配如果字符串中的当前位置不在前面   匹配...。这被称为负面的后观断言。   与正面的后观断言类似,包含的模式必须   只匹配某些固定长度的字符串,不应包含组   引用。以负后观断言开头的模式   可能在搜索字符串的开头匹配。

https://docs.python.org/3/library/re.html

答案 1 :(得分:3)

您可以使用否定后备(?<!\$)来表示“前面没有$”:

(?<!\$)\${[^}]*}

我简化了括号之间的部分,以便专注于“一个且只有一个$部分”。

这是regex101 link

答案 2 :(得分:1)

感谢Amber的想法。我按照你建议使用负面向前的相同思路。我用https://regex101.com/r/G2n0cO/1/尝试了所有这些。唯一一个几乎完美成功的是:

(?:^|[^\$])\${(?:(?P<section>[a-zA-Z0-9\-_]+?)\:)??(?P<key>[a-zA-Z0-9\-_]+?)(?:\[(?P<index>[0-9]+?)\])??\}

我仍然需要添加支票以删除最后一个非美元字符。在下面的示例结尾处。对于历史,自从我发布这个问题后,我保留了一些迭代:

    # keep tokens ${[section:][key][\[index\]]}and skip false ones 
    # pattern = r"\$\{((?P<section>.+?)\:)?(?P<key>.+?)(\[(?P<index>\d+?)\])+?\}" 
    # pattern = r'\$\{((?P<section>\S+?)\:)??(?P<key>\S+?)(\[(?P<index>\d+?)\])?\}'
    # pattern = r'\$\{((?P<section>[a-zA-Z0-9\-_]+?)\:)??(?P<key>[a-zA-Z0-9\-_]+?)(\[(?P<index>[0-9]+?)\])??\}'
    pattern = r'(?:^|[^\$])\${(?:(?P<section>[a-zA-Z0-9\-_]+?)\:)??(?P<key>[a-zA-Z0-9\-_]+?)(?:\[(?P<index>[0-9]+?)\])??\}'

    analyser = re.compile(pattern)
    mo = analyser.search(value, 0)
    log.debug(f'got match object: {mo}')
    while not mo is None:
        log.debug(f'in while loop, level={level}')

        if level > MAX_LEVEL:
            raise RecursionError(f"to many recursive call to _substiture_text() while processing '{value}'.")
        else:
            level +=1

        start = mo.start()
        end   = mo.end()
        # re also captured the first non $ sign symbol
        if value[start] != '$': 
            start += 1