【问题标题】:Multiply with find and replace与查找和替换相乘
【发布时间】:2011-02-11 15:57:09
【问题描述】:

可以用正则表达式进行算术运算吗?比如找到一个文件中的所有数字,然后乘以一个标量值。

【问题讨论】:

  • 我相信你可以破解它,但我发现任何“扩展”使用正则表达式都非常难以维护 - 即使用于预期目的,它们也会让人眼花缭乱!只是一个想法......
  • @Arrieta - 没错,正则表达式是要走的路。这是一个快速而肮脏的一次性脚本,因此不会引起维护者的愤怒。

标签: python regex sed


【解决方案1】:

正则表达式本身不能——它们都是关于文本的——所以 sed 不能直接。不过,用 python 或 perl 等完整的脚本语言来做类似的事情很容易。

【讨论】:

  • Sed 可以做到这一点。由于sed脚本中存在条件跳转,sed理论上是图灵完备的。实际上,脚本的长度和行数是有限制的。在互联网的某个地方,有一个用于完整计算器的 sed 脚本,包括 trig 和 exp 函数。但这种任务不是我会考虑使用 sed 的任务。
【解决方案2】:

您可以使用带有回调的re.sub() 实现此目的:

import re

def repl(matchobj):
  i = int(matchobj.group(0))
  return str(i * 2)

print re.sub(r'\d+', repl, '1 a20 300c')

输出:

2 a40 600c

来自文档:

re.sub(模式, repl, string[, 计数])

如果 repl 是一个函数,则调用它 对于每一个不重叠的事件 的图案。该函数采用 单个匹配对象参数,以及 返回替换字符串。

【讨论】:

  • 我不知道re.sub 的“迭代器质量”。感谢发帖。
  • 谢谢,您的解决方案非常优雅。这是很好的反馈!
【解决方案3】:

我准备了一个小脚本,它使用re.finditer 查找所有整数(您可以更改正则表达式,以便它可以处理浮点数或科学记数法),然后使用map 返回一个缩放数字列表。

import re

def scale(fact):
    """This function returns a lambda which will scale a number by a                           
    factor 'fact'"""
    return lambda val: fact * val

def find_and_scale(file, fact):
    """This function will find all the numbers (integers) in a file and                        
    return a list of all such numbers scaled by a factor 'fact'"""
    num = re.compile('(\d+)')
    scaling = scale(fact)
    f = open(file, 'r').read()
    numbers = [int(m.group(1)) for m in num.finditer(f)]
    return map(scaling, numbers)

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 3:
        print "usage: %s file factor" % sys.argv[0]
        sys.exit(-1)
    numbers = find_and_scale(sys.argv[1], int(sys.argv[2]))
    for number in numbers:
        print "%d " % number

如果您有一个file,您希望将其数字按系数fact 进行缩放,则从命令行调用脚本为python script.py file fact,它将打印到STDOUT 所有缩放的数字。当然,如果你愿意,你可以做一些更有用的事情......

【讨论】:

    【解决方案4】:

    在 perl 中,您可以使用 /e 修饰符来做到这一点。这会导致表达式的替换部分被计算。假设 $line 包含文件的一行

     my $scalar= 4;
     $line =~ s/([\d]+)/$1*$scalar/ge;
    

    将此应用于每一行将为您完成这项工作。例如将此应用于 $line 包含“foo2 bar25 baz”,将其转换为“foo8 bar100 baz”

    【讨论】:

    • 感谢您提醒我,perl 中始终存在单行解决方案。
    【解决方案5】:

    Ayman Hourieh 的答案可以简化为更简单一点,而且 imo 更具可读性:

    >>> import re
    >>> repl = lambda m: str(int(m.group(0)) * 2)
    >>> print re.sub(r'\d+', repl, '1 a20 300c')
    2 a40 600c
    

    【讨论】:

    • lambda 提供了一种创建匿名函数的方法。如果你最终给它一个名字,通常使用def会更清楚。
    • 这是一个见仁见智的问题,因为像这样的简单函数使用几行并不本质上是“更清晰”的。
    【解决方案6】:

    对于那些怀疑 sed 可以做算术的人,我提供了这个counter-exampleThis one 更加狂野。

    【讨论】:

    • 这些都是巧妙的技巧,但它们表明您必须非常有创意地使用 sed 才能获得算术结果。
    猜你喜欢
    • 1970-01-01
    • 2010-11-16
    • 2014-09-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 2012-02-12
    相关资源
    最近更新 更多