我有两个包含数字和文本的文件。两个文件中的文本是相同的。我想创建一个新文件,其中包含两个文件的平均数。
FileA.txt(超过10000行,超过1000个文本和数字)
External Host
FileB.txt(文本与FileA.txt相同)
textA
textB(10,2,2)
textC(2)
textD
.
.
FileNew.txt(具有FileA和FileB.txt的平均值)
textA
textB(0,0,4)
textC(4)
textD
.
.
一个请求是我不想更改任何文本。只需要更改数字。
我认为AWK或者差异化工作。
最佳,
Jaeyoung
答案 0 :(得分:3)
也许你可以尝试这样:
paste 'FileA' 'FileB'|awk '{if($0!~/\([0-9]+,[0-9]+,[0-9]+\)/){print $1;next}{split($1,f1,/[(),]/);split($2,f2,/[(),]/)};print f1[1] "(",int((f1[2]+f2[2])/2) "," int((f1[3]+f2[3])/2) "," int((f1[4]+f2[4])/2) ")"}'
以可读的方式打破这个
创建一个名为awkscript
的文件并附加这些行
#!/usr/bin/awk
{
if($0!~/\([0-9]+,[0-9]+,[0-9]+\)/){
print $1;next}
{split($1,f1,/[(),]/);split($2,f2,/[(),]/)};
print f1[1] "(",int((f1[2]+f2[2])/2) "," int((f1[3]+f2[3])/2) "," int((f1[4]+f2[4])/2) ")"
}
现在调用你的脚本
paste 'FileA' 'FileB'|awk -f 'awkscript'
(粘贴在这里派上用场)
结果
textA
textB( 5,1,3)
textC(2)
textD
.
.
答案 1 :(得分:0)
TXR解决方案:
@(next :list @(weave (get-lines (open-file [*args* 0]))
(get-lines (open-file [*args* 1]))))
@(repeat)
@ (cases)
@text(@cnum0)
@text(@cnum1)
@ (do (let* ((num0 [mapcar toint (split-str cnum0 ",")])
(num1 [mapcar toint (split-str cnum1 ",")])
(avg (mapcar (op trunc (+ @1 @2) 2) num0 num1)))
(put-line `@text(@{avg ","})`)))
@ (or)
@text
@text
@ (do (put-line text))
@ (end)
@(end)
$ txr avg.txr FileA.txt FileB.txt
textA
textB(5,1,3)
textC(3)
textD
.
.
此脚本处理文件,就好像它们是两个文件中包含行interleaved的文件一样。相应的文本必须完全匹配,否则程序将以失败的终止状态停止。与text(whatever)
语法不匹配的行被假定为必须完全匹配的文本。
假设数字是整数,并且在平均中使用截断除法。
这个纯粹的Lisp解决方案简单地将行分为数字和非数字部分,平均相应的数字部分。使用浮点数学。 tok-str
中的t
参数告诉它保留与标记化正则表达式不匹配的中间部分。
(each ((line0 (get-lines (open-file [*args* 0])))
(line1 (get-lines (open-file [*args* 1]))))
(let* ((nregex #/(\d+|\d+\.\d+|\.\d+)([Ee][+\-]?\d+)?/)
(chop0 (tok-str line0 nregex t))
(chop1 (tok-str line1 nregex t))
(out (mapcar (lambda (tok0 tok1)
(let ((n0 (tofloat tok0))
(n1 (tofloat tok1)))
(if (and n0 n1)
(/ (+ n0 n1) 2)
tok0)))
chop0 chop1)))
(put-line `@{out ""}`)))
$ txr avg.tl FileA.txt FileB.txt
textA
textB(5.0,1.0,3.0)
textC(3.0)
textD
.
.