我需要在字符串中的任何位置匹配以下内容之一:
${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"[^\$|^]
有什么建议吗?
答案 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
(?<!...)
匹配如果字符串中的当前位置不在前面 匹配
...
。这被称为负面的后观断言。 与正面的后观断言类似,包含的模式必须 只匹配某些固定长度的字符串,不应包含组 引用。以负后观断言开头的模式 可能在搜索字符串的开头匹配。
答案 1 :(得分:3)
答案 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