问题描述
我正在扫描“.twig”(PHP模板)文件并尝试捕获对象的属性名称。
twig文件包含这些行(字符串):
{{ 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
。
这是不可能的,还是我错过了什么?
我可以捕获( "{{.+?product((?:\\.[a-zA-Z]+(?:\\(.+?\\)){,1})+).+?}}"
)它作为一个整体( .countdown.startDate
),然后检查/拆分它,但这听起来很麻烦。
1楼
如果您想使用单个正则表达式来处理它,您可能想要使用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)']
请参阅
{{[^{}]*product(\\.[a-zA-Z]+(?:\\([^()]+\\))?)*[^{}]*}}
正则表达式将匹配
-
{{
-{{
substring -
[^{}]*
- 除了{
和}
之外的0{
字符 -
product
- 子串product
-
(\\.[a-zA-Z]+(?:\\([^()]+\\))?)*
- 捕获组1:零个或多个序列-
\\.
- 一个点 -
[a-zA-Z]+
- 1+ ASCII字母 -
(?:\\([^()]+\\))?
- 可选的序列(
除了(
和)
之外的1+个字符然后)
-
-
[^{}]*
- 除了{
和}
之外的0{
字符 -
}}
- a}}
substring。
如果你只限于re
,你需要将所有属性捕获到1个捕获组中(包装它(\\.[a-zA-Z]+(?:\\([^()]+\\))?)*
with (...)
)然后运行基于正则表达式的后处理进行拆分.
不在括号内:
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)']
请参阅
2楼
尝试这个,捕获你的要求
^{{ product(\..*?[(][^\d\/]+[)]).*?}}|^{{ product(\..*?)(\..*?)?(?= )
3楼
我决定坚持使用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)"
}