我有一个 STIX 模式如下:
stix_ptn_and_or_case2 = '''[(x:x.x = 'A' OR x:x.x = 'B' ) AND ( x:x.x = 'C' OR x:x.x = 'D' )]'''
模式的逻辑是(A OR B) AND (C OR D)
该模式可以通过 dendrol(python 库)解析为表达式树,如下所示
(A OR B) AND (C OR D)
的逻辑可以拆分成下面4个小的AND only logic
- A
AND
C
- A
AND
D
- B
AND
C
- B
AND
D
我想解析表达式树以获得4个AND only逻辑
所以我写了如下的python代码。 python 库 dendrol 可以将 STIX 模式转换为表达式树。
import os, sys, datetime, copy
from dendrol import Pattern
stix_ptn_and_or_case2 = '''[(x:x.x = 'A' OR x:x.x = 'B' ) AND ( x:x.x = 'C' OR x:x.x = 'D' )]'''
ptn = Pattern(stix_ptn_and_or_case2)
pdt = ptn.to_dict_tree()
obj = pdt['pattern']
all_ptn_element_list = []
# the recursion function for expression tree to and-only logic
def ptnct(obj, ptn_element_list):
if('observation' in obj or 'expression' in obj):
if('observation' in obj):
join = obj['observation']['join']
expressions = obj['observation']['expressions']
else:
join = obj['expression']['join']
expressions = obj['expression']['expressions']
if(join=='AND' or join==None):
for exp in expressions:
p = ptnct(exp, ptn_element_list)
if(p!=None):
ptn_element_list.append(p)
if(len(ptn_element_list)==len(expressions)):# all and
all_ptn_element_list.append(ptn_element_list)
elif(join=='OR'):
for exp in expressions:
p = ptnct(exp, ptn_element_list)
tmp = copy.deepcopy( ptn_element_list )
tmp.append(p)
all_ptn_element_list.append(tmp)
elif('comparison' in obj):
exp = obj
tag = '{0}:{1}.{2}'.format(exp['comparison']['object'], exp['comparison']['path'][0], exp['comparison']['path'][1])
value = exp['comparison']['value']
return value
x=ptnct(obj, [])
print(all_ptn_element_list)
代码的输出是
[[u'A'], [u'B'], [u'C'], [u'D']]
但是想要的输出是
[[u'A', u'C'], [u'A', u'D'], [u'B', u'C'], [u'B', u'D']]
实际上代码适用于大多数情况,但不适用于此。
对于将 AND-OR 逻辑表达式树解析为 AND-only 表达式(模式)有什么建议吗?
使用方便的 itertools.product
和 itertools.chain
,我们可以将分离表达式树转换为所有可能的连接表达式列表
from itertools import product, chain
from dendrol import Pattern
def extract_atomic_chunks(root):
container = root.get('observation') or root.get('expression')
comparison = root.get('comparison')
if container:
join = container['join']
expressions = container['expressions']
if join == 'OR':
# Return all possibilities under this node
return chain(
extract_atomic_chunks(expression)
for expression in expressions
)
elif join == 'AND':
# Generate all possible N-tuples, where N=len(expressions)
groups = [
extract_atomic_chunks(expression)
for expression in expressions
]
return product(*groups)
elif comparison:
return comparison['value']
if __name__ == '__main__':
stix_expr = "[(x:x.x = 'A' OR x:x.x = 'B') AND (x:x.x = 'C' OR x:x.x = 'D')]"
pattern = Pattern(stix_expr)
tree = pattern.to_dict_tree()
root = tree['pattern']
print(list(extract_atomic_chunks(root)))
我想这会让你到达你想要的地方
[('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D')]
我是一名优秀的程序员,十分优秀!