2010-04-23 30 views
3

可以使用正則表達式來執行算術嗎?如查找文件中的所有數字並將其乘以標量值。與查找和替換相乘

+0

我敢肯定,你可以通過它破解你的方式,但我發現任何「擴展」使用高度不可維護的正則表達式 - 即使用於其預期目的,它們也是眼睛疼痛!只是一個想法... – Escualo 2010-04-23 19:13:22

+0

@Arrieta - 真的,正則表達式是要走的路。這是一個快速和骯髒的一次性腳本,所以沒有維護者的憤怒將隨之而來。 – cdated 2010-04-24 15:28:33

回答

2

我準備了使用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所有縮放數字。當然,如果你想要的話,你可以做些更有用的事情......

+0

謝謝,這完全符合我的想法。 – cdated 2010-04-24 14:45:18

1

正則表達式本身不能 - 它們都是關於文本的 - 所以sed不能直接。不過,使用像python或perl這樣的完整腳本語言來完成類似的事情是很容易的。

+0

Sed可以做到這一點。由於sed腳本中存在條件跳轉,sed在理論上是完整的。實際上,腳本中的行數和長度是有限制的。在互聯網上的某個地方,有一個完整的計算器的sed腳本,包括trig和exp函數。但是那種任務並不是我會考慮使用sed的那種。 – 2010-04-25 10:20:23

8

你可以做到這一點使用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,字符串[ , count])

如果repl是一個函數,則它被稱爲 ,用於模式的每個非重疊事件 。該函數採用 單個匹配對象參數,並且 返回替換字符串。

+1

我不知道're.sub'的'迭代器質量'。感謝發佈。 – Escualo 2010-04-23 19:14:53

+0

謝謝,您的解決方案非常優雅。這是很好的反饋! – cdated 2010-04-24 14:54:26

4

在perl中,你可以用/ e修飾符來做到這一點。這會導致評估表達式的替換部分。假設$ line包含文件的一行

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

將此應用於每一行將爲您完成這項工作。例如將這種含有「foo2的bar25巴茲」一 $線,轉變爲「foo8 bar100巴茲」

+0

感謝您提醒我,perl中始終存在一行解決方案。 – cdated 2010-04-24 15:10:22

-1

艾曼Hourieh的回答可以減少到一點點簡單的,和國際海事組織更具可讀性:

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

'lambda'提供了一種創建匿名函數的方法。如果你最終給它一個名字,通常使用'def'更清晰。 – 2010-04-24 01:02:02

+0

這是一個意見問題,因爲像這樣使用幾行代替一個簡單的函數本質上不是「更清晰」。 – 2010-04-25 15:38:32

1

對於那些懷疑sed可以算術的人,我提供counter-exampleThis one更加狂野。

+0

這些都是巧妙的技巧,但它們表明你必須非常有創意,用sed來獲得算術結果。 – cdated 2010-04-24 14:59:52