python 文本处理2
接上文,我們定義了判斷某行是否file copy,或者file overwrite的兩個函數,事實上我們如果使用
startswith函數代替slice,會更穩定。從函數式編程角度,我們給出下面幾個表達式:
????? isRegDBRoot = lambda line: line[:11]=='RegDB Root:'
????? isRegDBKey = lambda line: line[:10]=='RegDB Key:'
????? isRegDBVal = lambda line: line[:10]=='RegDB Val:'
有了這三個更加緊湊的函數,我們給出之前方法的函數式編程寫法;
????? lines = open(r'd:\python22\install.log').readlines()
????? regroot_lines = filter(isRegDBRoot, lines)
如果,你想通過多個選擇標準來選擇相應的行,那么函數式的寫法就會顯得笨拙。
我們可以根據相似的思路寫出一個給定要求對應的過濾函數如下:
?#*--------------- Find the RegDB lines ------------------#
????? def isAnyRegDB(line):
????????? if?? line[:11]=='RegDB Root:': return 1
????????? elif line[:10]=='RegDB Key:':? return 1
????????? elif line[:10]=='RegDB Val:':? return 1
????????? else:????????????????????????? return 0
但是,如果需求變成了其他的組合呢?顯然依據這個思路,我們必須為另外的組合寫更多的組合,這種組合是爆炸性的增長的。。。另外的思路是通過嵌套過濾函數來達到:
?#*------------- Filter on two line predicates -----------#
????? shortline = lambda line: len(line) < 25
????? short_regvals = filter(shortline, filter(isRegDBVal, lines))
這樣的思路寫出的程序比較容易排錯,該函數使用了兩個已有的函數來生成新的程序。但是一個顯而易見的問題是:這樣的程序很難閱讀。同樣的問題也出現在map函數上。通常解決這樣問題的方法是多增加一些循環和中間變量。。
根據函授式編程的思路,我們可以在不增加代碼量的情況下解決上面描述的問題。
這里的關鍵點是:選擇的生成一些高級別的組合函數:這里的高級別函數是指:那些接受函數作為輸入,返回函數作為輸出的函數。一級函數接受數據,返回數據。相對應的一個高級函數的輸入和輸出都是函數對象。這些函數對象將在未來被其他地方使用:高級函數的一個例子是;函數工廠,它返回一個或者一組函數對象。下面是一個加法函數工廠;
>>> def adder_factory(n):
????? ...??? return lambda m, n=n: m+n
????? ...
????? >>> add10 = adder_factory(10)
????? >>> add10
????? <function <lambda> at 0x00FB0020>
????? >>> add10(4)
????? 14
????? >>> add10(20)
????? 30
????? >>> add5 = adder_factory(5)
????? >>> add5(4)
????? 9
回到正題,我們提到用高級組合函數來解決前面提到的問題,這些高級函數通過接受一些函數,對這些函數對象進行操作從而合成其他的函數。下面是一個組合高級函數庫:
#------------------- combinatorial.py -------------------#
????? from operator import mul, add, truth
????? apply_each = lambda fns, args=[]: map(apply, fns, [args]*len(fns))
????? bools = lambda lst: map(truth, lst)
????? bool_each = lambda fns, args=[]: bools(apply_each(fns, args))
????? conjoin = lambda fns, args=[]: reduce(mul, bool_each(fns, args))
????? all = lambda fns: lambda arg, fns=fns: conjoin(fns, (arg,))
????? both = lambda f,g: all((f,g))
????? all3 = lambda f,g,h: all((f,g,h))
????? and_ = lambda f,g: lambda x, f=f, g=g: f(x) and g(x)
????? disjoin = lambda fns, args=[]: reduce(add, bool_each(fns, args))
????? some = lambda fns: lambda arg, fns=fns: disjoin(fns, (arg,))
????? either = lambda f,g: some((f,g))
????? anyof3 = lambda f,g,h: some((f,g,h))
????? compose = lambda f,g: lambda x, f=f, g=g: f(g(x))
????? compose3 = lambda f,g,h: lambda x, f=f, g=g, h=h: f(g(h(x)))
????? ident = lambda x: x
這樣通過使用這些高級組合函數:我們可以這樣解決之前遇到的問題:
?#----- Some examples using higher-order functions -----#
????? # Don't nest filters, just produce func that does both
????? short_regvals = filter(both(shortline, isRegVal), lines)
????? # Don't multiply ad hoc functions, just describe need
????? regroot_lines = \
????????? filter(some([isRegDBRoot, isRegDBKey, isRegDBVal]), lines)
????? # Don't nest transformations, make one combined transform
????? capFlipNorm = compose3(upper, flip, normalize)
????? cap_flip_norms = map(capFlipNorm, lines)
可以看出通過函數式編程方法,我們可以不僅獲得更加精煉的代碼,以及更好的可讀性.
任何嵌套的filter 和map函數都可以通過高級組合函數進行化簡,總的來說,函數式編程方法得到的代碼量應該在常規方法代碼量的一半。
這種高級組合函數的另外一個好處是;他們可以提供一整套的函數的布爾表達式。
? #*---------- Simple Boolean algebra of values ----------#
????? satisfied = (this or that) and (foo or bar)
在文本處理環境下,這樣的操作經常是一些predic函數的結果。如下:
? #*---------- Boolean algebra of return values ----------#
????? satisfied = (thisP(s) or thatP(s)) and (fooP(s) or barP(s))
通過之前的高級組合函數,我們可以得到如下代碼:
?#*------ Boolean algebra of composed functions ------#
????? satisfiedP = both(either(thisP,thatP), either(fooP,barP))
精簡如斯啊。
一些問題下次再翻譯,睡了。
轉載于:https://www.cnblogs.com/zhangsong/archive/2012/07/10/2585412.html
總結
以上是生活随笔為你收集整理的python 文本处理2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: T-SQL 中ON和WHERE的区别
- 下一篇: 使用C语言扩展Python(四)