我在python中处理一些json格式的日志文件。编写一些条件查询非常简单,例如
Dim iRisks() As String = {"$70"}
Dim allTicks() As String = {"1.0", "1.1"}
Dim iTimes() As String = {"210", "220", "240"}
For Each iRisk In iRisks
For Each iTime In iTimes
For Each eachTick In allTicks
Dim iThread1 As New Threading.Thread(New Threading.ParameterizedThreadStart(AddressOf FindStats))
iThread1.Start(eachTick & "|" & iTime & "|" & iRisk)
Next
Next
Next
有没有办法 安全地 将字符串解释为条件表达式的一部分,这样我就可以在命令行上接受条件并使其成为我的一部分查询?
line=[1,'runtime',{'elapsed':12.3,'jobname':'high38853'}] # read from json
# split the record and see what jobs take over 30 seconds
key,category,details=line
if category == 'runtime' and details['elapsed'] > 30:
print details
所以在代码中我可以做这样的事情吗?
search 'details["elapsed"] > 30'
答案 0 :(得分:3)
这应该做你想要的:
from __future__ import print_function
import ast
import operator
import sys
OPERATORS = {
'<': operator.lt,
'<=': operator.le,
'>': operator.gt,
'>=': operator.ge,
'==': operator.eq,
'!=': operator.ne,
# 'in' is using a lambda because of the opposite operator order
# 'in': (lambda item, container: operator.contains(container, item),
'in': (lambda item, container: item in container),
'contains': operator.contains,
}
def process_conditionals(conditional_strings, variables):
for conditional_string in conditional_strings:
# Everything after first and op is part of second
first, op, second = conditional_string.split(None, 2)
resolved_operands = []
for raw_operand in (first, second):
try:
resolved_operand = ast.literal_eval(raw_operand)
except ValueError: # If the operand is not a valid literal
ve = sys.exc_info()
try:
# Check if the operand is a known value
resolved_operand = variables[raw_operand]
except KeyError: # If the operand is not a known value
# Re-raise the ValueError
raise ve[1], None, ve[2]
resolved_operands.append(resolved_operand)
yield (op, tuple(resolved_operands))
def main(lines, *conditional_strings):
for line in lines:
key, category, details = line
variables = {
'key': key,
'category': category,
'elapsed': details['elapsed'],
'jobname': details['jobname'],
}
conditionals = process_conditionals(conditional_strings, variables)
try:
# You could check each conditional separately to determine
# which ones have errors.
condition = all(OPERATORS[op](*operands)
for op, operands in conditionals)
except TypeError:
print("A literal in one of your conditionals is the wrong type. "
"If you can't see it, try running each one separately.",
file=sys.stderr)
break
except ValueError:
print("An operand in one of your conditionals is neither a known "
"variable nor a valid literal. If you can't see it, try "
"running each one separately.", file=sys.stderr)
break
else:
if condition:
print(line)
if __name__ == '__main__':
lines = [
[1, 'runtime', {'elapsed': 12.3, 'jobname': 'high38853'}],
[2, 'runtime', {'elapsed': 45.6, 'jobname': 'high38854'}],
[3, 'runtime', {'elapsed': 78.9, 'jobname': 'high38855'}],
[4, 'runtime', {'elapsed': 14.7, 'jobname': 'high38856'}],
[5, 'runtime', {'elapsed': 25.8, 'jobname': 'high38857'}],
[6, 'runtime', {'elapsed': 36.9, 'jobname': 'high38858'}],
[7, 'runtime', {'elapsed': 75.3, 'jobname': 'high38859'}],
]
conditional_strings = sys.argv[1:]
main(lines, *conditional_strings)
示例:
$ ./SO_31999444.py 'elapsed > 30'
[2, 'runtime', {'jobname': 'high38854', 'elapsed': 45.6}]
[3, 'runtime', {'jobname': 'high38855', 'elapsed': 78.9}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
[7, 'runtime', {'jobname': 'high38859', 'elapsed': 75.3}]
$ ./SO_31999444.py 'elapsed > 20' 'elapsed < 50'
[2, 'runtime', {'jobname': 'high38854', 'elapsed': 45.6}]
[5, 'runtime', {'jobname': 'high38857', 'elapsed': 25.8}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
$ ./SO_31999444.py 'elapsed > 20' 'elapsed < 50' 'key >= 5'
[5, 'runtime', {'jobname': 'high38857', 'elapsed': 25.8}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
$ ./SO_31999444.py "'9' in jobname"
[7, 'runtime', {'jobname': 'high38859', 'elapsed': 75.3}]
$ ./SO_31999444.py "jobname contains '9'"
[7, 'runtime', {'jobname': 'high38859', 'elapsed': 75.3}]
$ ./SO_31999444.py "jobname in ['high38857', 'high38858']"
[5, 'runtime', {'jobname': 'high38857', 'elapsed': 25.8}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
$ ./SO_31999444.py "9 in jobname"
A literal in one of your conditionals is the wrong type. If you can't see it, try running each one separately.
$ ./SO_31999444.py "notakey == 'something'"
An operand in one of your conditionals is neither a known variable nor a valid literal. If you can't see it, try running each one separately.
$ ./SO_31999444.py "2 == 2"
[1, 'runtime', {'jobname': 'high38853', 'elapsed': 12.3}]
[2, 'runtime', {'jobname': 'high38854', 'elapsed': 45.6}]
[3, 'runtime', {'jobname': 'high38855', 'elapsed': 78.9}]
[4, 'runtime', {'jobname': 'high38856', 'elapsed': 14.7}]
[5, 'runtime', {'jobname': 'high38857', 'elapsed': 25.8}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
[7, 'runtime', {'jobname': 'high38859', 'elapsed': 75.3}]
$ ./SO_31999444.py
[1, 'runtime', {'jobname': 'high38853', 'elapsed': 12.3}]
[2, 'runtime', {'jobname': 'high38854', 'elapsed': 45.6}]
[3, 'runtime', {'jobname': 'high38855', 'elapsed': 78.9}]
[4, 'runtime', {'jobname': 'high38856', 'elapsed': 14.7}]
[5, 'runtime', {'jobname': 'high38857', 'elapsed': 25.8}]
[6, 'runtime', {'jobname': 'high38858', 'elapsed': 36.9}]
[7, 'runtime', {'jobname': 'high38859', 'elapsed': 75.3}]
这是一个有趣的小项目:)。
答案 1 :(得分:0)
实际上没有一种安全的方法可以做到这一点。对于基本条件,您可以解析特定格式的输入字符串。如果您输入的格式为“var&gt; 5”,则可以像这样解析它:
var, op, num = argv[1].split()
var = getattr(sys.modules[__name__], var) # Get a reference to the data
num = int(num)
if op == ">":
r = var > num
elif op == "<":
r = var < num
...
if r:
<do stuff>
要支持更复杂的语句,您需要改进解析器。如果您不信任您的输入,则应将getattr和int包装在try / except块中。要支持int或float或其他var,你需要相当多的逻辑。