捕获属性名称

时间:2018-09-22 19:48:33

标签: python regex

我正在扫描“ .twig”(PHP模板)文件,并试图捕获对象的属性名称。

嫩枝文件包含以下行(字符串):

{{ product.id }}
{{ product.parentProductId }}
{{ product.countdown.startDate | date('Y/m/d H:i:s') }}
{{ product.countdown.endDate | date('Y/m/d H:i:s') }}
{{ product.countdown.expireDate | date('Y/m/d H:i:s') }}
{{ product.primaryImage.originalUrl }}
{{ product.image(1).originalUrl }}
{{ product.image(1).thumbUrl }}
{{ product.priceWithTax(preferences.default_currency) | money }}

我要捕获的东西是:

.id
.parentProductId
.countdown
.startDate
.endDate
.expireDate
.primaryImage
.originalUrl
.image(1)
.originalUrl
.thumbUrl
.priceWithTax(preferences.default_currency)

基本上,我试图找出product对象的属性。我有以下模式,但是它不捕获链接的属性。例如,

"{{.+?product(\.[a-zA-Z]+(?:\(.+?\)){,1})++.+?}}"仅捕获.startDate,但应分别捕获.countdown.startDate。这是不可能的,还是我错过了什么?

regex101

我可以将("{{.+?product((?:\.[a-zA-Z]+(?:\(.+?\)){,1})+).+?}}")整体捕获(.countdown.startDate),然后再检查/拆分,但这听起来很麻烦。

3 个答案:

答案 0 :(得分:2)

如果要使用单个正则表达式处理它,则可能要使用PyPi regex模块:

import regex

s = """{{ product.id }}
{{ product.parentProductId }}
{{ product.countdown.startDate | date('Y/m/d H:i:s') }}
{{ product.primaryImage.originalUrl }}
{{ product.image(1).originalUrl }}
{{ product.priceWithTax(preferences.default_currency) | money }}"""

rx = r'{{[^{}]*product(\.[a-zA-Z]+(?:\([^()]+\))?)*[^{}]*}}'

l = [m.captures(1) for m in regex.finditer(rx, s)]

print([item for sublist in l for item in sublist])
# => ['.id', '.parentProductId', '.countdown', '.startDate', '.primaryImage', '.originalUrl', '.image(1)', '.originalUrl', '.priceWithTax(preferences.default_currency)']

请参见Python demo

{{[^{}]*product(\.[a-zA-Z]+(?:\([^()]+\))?)*[^{}]*}}正则表达式将匹配

  • {{-{{子字符串
  • [^{}]*-除{}以外的0多个字符
  • product-子字符串product
  • (\.[a-zA-Z]+(?:\([^()]+\))?)*-捕获第1组:零个或多个序列
    • \.-一个点
    • [a-zA-Z]+-1个以上ASCII字母
    • (?:\([^()]+\))?-可选的(序列,除了()以外的1个字符,然后是)
  • [^{}]*-除{}以外的0多个字符
  • }}-一个}}子字符串。

如果仅限于re,则需要将所有属性捕获到1个捕获组中(用(\.[a-zA-Z]+(?:\([^()]+\))?)*包裹此(...)),然后运行基于正则表达式的post-由.分隔而不在括号内的过程:

import re
rx = r'{{[^{}]*product((?:\.[a-zA-Z]+(?:\([^()]+\))?)*)[^{}]*}}'
l = re.findall(rx, s)
res = []
for m in l:
     res.extend([".{}".format(n) for n in filter(None, re.split(r'\.(?![^()]*\))', m))])
print(res)
# => ['.id', '.parentProductId', '.countdown', '.startDate', '.primaryImage', '.originalUrl', '.image(1)', '.originalUrl', '.priceWithTax(preferences.default_currency)']

请参见this Python demo

答案 1 :(得分:0)

尝试一下,捕获您所有的需求

^{{ product(\..*?[(][^\d\/]+[)]).*?}}|^{{ product(\..*?)(\..*?)?(?= )

demo and explanation at regex 101

答案 2 :(得分:0)

我决定坚持使用re(而不是像Victor所建议的regex),这就是我最终得到的结果:

import re, json

file = open("test.twig", "r", encoding="utf-8")
content = file.read()
file.close()

patterns = {
    "template"  : r"{{[^{}]*product((?:\.[a-zA-Z]+(?:\([^()]+\))?)*)[^{}]*}}",
    "prop"      : r"^[^\.]+$",                  # .id
    "subprop"   : r"^[^\.()]+(\.[^\.]+)+$",     # .countdown.startDate
    "itemprop"  : r"^[^\.]+\(\d+\)\.[^\.]+$",   # .image(1).originalUrl
    "method"    : r"^[^\.]+\(.+\)$",            # .priceWithTax(preferences.default_currency)
}

temp_re = re.compile(patterns["template"])
matches = temp_re.findall(content)

product = {}

for match in matches:
    match = match[1:]
    if re.match(patterns["prop"], match):
        product[match] = match
    elif re.match(patterns["subprop"], match):
        match = match.split(".")
        if match[0] not in product:
            product[match[0]] = []
        if match[1] not in product[match[0]]:
            product[match[0]].append(match[1])
    elif re.match(patterns["itemprop"], match):
        match = match.split(".")
        array = re.sub("\(\d+\)", "(i)", match[0])
        if array not in product:
            product[array] = []
        if match[1] not in product[array]:
            product[array].append(match[1])
    elif re.match(patterns["method"], match):
        product[match] = match

props = json.dumps(product, indent=4)

print(props)

示例输出:

{
    "id": "id",
    "parentProductId": "parentProductId",
    "countdown": [
        "startDate",
        "endDate",
        "expireDate"
    ],
    "primaryImage": [
        "originalUrl"
    ],
    "image(i)": [
        "originalUrl",
        "thumbUrl"
    ],
    "priceWithTax(preferences.default_currency)": "priceWithTax(preferences.default_currency)"
}