【问题标题】:replacing variable names in string with values from list and avoiding redundant replaces用列表中的值替换字符串中的变量名并避免冗余替换
【发布时间】:2012-07-09 23:12:33
【问题描述】:

给定一个 eval 方程:

    eval_str = 'VAR1 > 0 and VAR1 < 10 and (VAR2 == VAR1::VALUE_X or VAR2 == VAR2::VALUE_X)'

任务:我需要用它们的实际值替换变量(本例中为 VAR1、VAR2),并用引号将给定的“常量”(VAR1::VALUE_X) 括起来。

问题:由于变量名存在于常量和 eval 字符串中,并且由于变量可以替换为包含变量名本身的字符串 - 我遇到了常量值中的变量名将被替换的问题由另一个常量或变量值。更好地展示...

     eval_str = '(VAR2 == VAR2::VALUE_X or VAR2 != VAR2::VALUE_Z) and (VAR1 > 0 and VAR1 < 10)'
     var_dict = {'VAR1':'5','VAR2':'VAR1::VALUE_Y'}

     # what I do is strip out most of the special characters
     # the following findall = ['VAR1', '0', 'and', 'VAR1', '10', 'and', 'VAR2', 'VAR1::VALUE_X', 'or', 'VAR2', 'VAR2::VALUE_X']
     for x in re.findall('[^\s()<>=!]+',eval_str):
        # skip digits, and, or, None *need to improve regex
        if x.replace('.','').isdigit() or x == 'and' or x == 'or' or x == 'None':
           continue
        # if variable is in dict
        if x in var_dict.keys():
           # only replace first
           eval_str = eval_str.replace(x,var_dict[x],1) 
        # if is constant
        elif x.__contains__('::'):
           eval_str = eval_str.replace(x,'\'%s\''%x,1)

     print eval_str
     # (5::VALUE_Y == '5::VALUE_Y::VALUE_X' or VAR2 != 'VAR2::VALUE_Z') and (VAR1 > 0 and VAR1 < 10)

与其通过每个变量/值递增,不如为每个变量/值都使用正则表达式替换它们会更好?或者,如果有办法在每次替换后记住我在字符串中的位置,我可以修复我现有的解决方案吗?

TYVM!

【问题讨论】:

  • 这应该是解析器的一部分吗?
  • 这些是来自以前框架的验证字符串,他们应该只是简单地传递给 eval() 调用,但现在我必须注入实际值,因为这些变量不再适用。跨度>

标签: python string list replace


【解决方案1】:

看起来(在我看来)使用字符串格式化可以更轻松地完成 - 假设您对输入字符串有一点控制:

>>> d={'action':'bar','verb':'foo'}
>>> print ("don't %(action)s a %(verb)s"%d)

或者这个怎​​么样:

import re
class DictFormatter(dict):
    def __missing__(self,k):
        return k

eval_str = '(VAR2 == VAR2::VALUE_X or VAR2 != VAR2::VALUE_Z) and (VAR1 > 0 and VAR1 < 10)'
var_dict = DictFormatter()
var_dict.update({'VAR1':'5','VAR2':'VAR1::VALUE_Y'})

extra_space = re.compile(r'[\w:]+')  #words are alphanumeric + ':' + '_'.
eval_str = extra_space.sub(lambda m: ' %s '%(m.group()),eval_str) #make sure there is space between "words"
eval_list = [var_dict[item] for item in eval_str.split()]

print " ".join(eval_list)

【讨论】:

  • 不幸的是,我对输入字符串的控制为零
【解决方案2】:

要替换 VAR1 离开 VAR1::VALUE_X,您可以使用否定前瞻:

string = re.sub(r'VAR\d(?!\:\:)', lambda m: var_dict[m.group(0)], string)

更强大的解决方案是将字符串解析为 AST 并对其进行评估。

【讨论】:

  • 这行得通,但是我必须验证该变量仅单独存在或在 :: 之前存在,但它也存在为:VAR1:Instance{1},这将如何影响前瞻? VAR\d(?!\:)(?!\:\:) ??
猜你喜欢
  • 2020-08-14
  • 1970-01-01
  • 1970-01-01
  • 2014-06-12
  • 2020-09-04
  • 2017-06-21
  • 2020-02-04
  • 1970-01-01
相关资源
最近更新 更多