如何将文件中的所有数值都除以某一个数

yswzing
yswzing 2013-06-19 字数 421

如何实现这样的需求,将文件中的所有形如 (x, y) 的串替换成 (x', y'),其中:

1. x, y 都是 NNNN.NNNN 或 NNNN 的数值;

2. x' = x/0.7, y' = y/0.7;

3. 一行中可能有多个 (x, y) 组,个数不确定,每行的格式不一致;

vim, sed, awk 都有什么好的解决方法?因为文件很大,最好是可以用 sed/awk 实现。

初步的想法是用 s 命令,比如 s_(\([0-9.]*\), \([0-9.]*\))_(\1/0.7, \2/0.7)_g,但是不行,\1/0.7 没有被计算成数值,而是被当作字符串直接插入进去了。

VIM VI编辑器
16 个回复
rezilla
@_0 2013-06-19

:%s#(\([0-9.]*\), \([0-9.]*\))#\= '(' . printf("%f", submatch(1) / 0.7) . ', ' .

printf("%f", submatch(2) / 0.7) . ')'#g

不知道是否你想要的?其中

%f可以控制输出精度

不过感觉这个用perl应该更合适吧

【 在 yswzing (yswzing) 的大作中提到: 】

: 如何实现这样的需求,将文件中的所有形如 (x, y) 的串替换成 (x', y'),其中:

: 1. x, y 都是 NNNN.NNNN 或 NNNN 的数值;

: 2. x' = x/0.7, y' = y/0.7;

: ...................

yswzing
yswzing 2013-06-19

[em66] 正是我想要的,谢谢!

如果用 Perl 实现的话,应该怎么做,能否在几条语句内完成?

【 在 rezilla 的大作中提到: 】

: :%s#(\([0-9.]*\), \([0-9.]*\))#\= '(' . printf("%f", submatch(1) / 0.7) . ', ' .

: printf("%f", submatch(2) / 0.7) . ')'#g

: 不知道是否你想要的?其中

: ...................

milksea
肥了,又肥了 >>>_<<< 2013-06-19

如果一行只有一个数据,awk 还可以。感觉一行多个数据就不大合适了。

【 在 rezilla (@_0) 的大作中提到: 】

: :%s#(\([0-9.]*\), \([0-9.]*\))#\= '(' . printf("%f", submatch(1) / 0.7) . ', ' .

: printf("%f", submatch(2) / 0.7) . ')'#g

: 不知道是否你想要的?其中

: ...................

yswzing
yswzing 2013-06-19

最开始尝试的就是 awk,最初的想法是用一个 gensub 命令实现:

awk '{print gensub("\(([0-9.]*), ([0-9.]*)\)", “(" "\\1"/0.7 "\\2"/0.7 ")", "g")}'

但是发现 "\\1"/0.7 这种形式不行,直接输出 0,而不是 \\1 除以 0.7 的结果,

试过 strtonum("\\1")/0.7,也不行,可能 gensub 的第二个参数不能是一个表达式,

只能是一个字符串。

milksea 能不能指点一下。如果能用 awk 实现的话,处理大文件确实方便很多。

【 在 milksea 的大作中提到: 】

: 感觉 awk 合适

milksea
肥了,又肥了 >>>_<<< 2013-06-19

我也不是很懂这个……

【 在 yswzing (yswzing) 的大作中提到: 】

: 最开始尝试的就是 awk,最初的想法是用一个 gensub 命令实现:

: awk '{print gensub("\(([0-9.]*), ([0-9.]*)\)", “(" "\\1"/0.7 "\\2"/0.7 ")", "g")}'

: 但是发现 "\\1"/0.7 这种形式不行,直接输出 0,而不是 \\1 除以 0.7 的结果,

: ...................

milksea
肥了,又肥了 >>>_<<< 2013-06-19

每行只有一个的话,用这样的办法就行

{

match($0, /\(([0-9.]*), *([0-9.]*)\)/, arr)

print "(" arr[1]/0.7 ",", arr[2]/0.7 ")"

}

【 在 yswzing (yswzing) 的大作中提到: 】

: 最开始尝试的就是 awk,最初的想法是用一个 gensub 命令实现:

: awk '{print gensub("\(([0-9.]*), ([0-9.]*)\)", “(" "\\1"/0.7 "\\2"/0.7 ")", "g")}'

: 但是发现 "\\1"/0.7 这种形式不行,直接输出 0,而不是 \\1 除以 0.7 的结果,

: ...................

yswzing
yswzing 2013-06-19

有一点需要说明,文件中不光有 (x, y) 元组,还有其它很多无关内容。

sed 的问题是 s/pattern/.../ 中的 ... 不能做算术运算;

awk 的问题是 gensub/pattern/.../ 中的 ... 不能是表达式;

这么一个简单的需求,本以为 sed/awk 可以轻松搞定,看来还是有难度啊,可能 perl 会有一个 elegant 的解决方案。

rezilla
@_0 2013-06-19

perl不怎么熟练,献丑了 版主看见别笑话我

$ cat b.txt

(123, 434)

(222, 2)

$ perl -pi.bak -e 's#\(([0-9.]*), ([0-9.]*)\)#"(" . $1 / 0.7. ", " . $2 / 0.7. ")"#ge' b.txt

$ cat b.txt

(175.714285714286, 620)

(317.142857142857, 2.85714285714286)

$ cat b.txt.bak

(123, 434)

(222, 2)

要控制精度的话可能得用printf,不过在eval里用会把返回值也打出来,不知道怎么去。。。

【 在 yswzing (yswzing) 的大作中提到: 】

: 有一点需要说明,文件中不光有 (x, y) 元组,还有其它很多无关内容。

: sed 的问题是 s/pattern/.../ 中的 ... 不能做算术运算;

: awk 的问题是 gensub/pattern/.../ 中的 ... 不能是表达式;

: ...................

milksea
肥了,又肥了 >>>_<<< 2013-06-19

其实这么长时间我用 C 都写完了……

【 在 yswzing (yswzing) 的大作中提到: 】

: 有一点需要说明,文件中不光有 (x, y) 元组,还有其它很多无关内容。

: sed 的问题是 s/pattern/.../ 中的 ... 不能做算术运算;

: awk 的问题是 gensub/pattern/.../ 中的 ... 不能是表达式;

: ...................

yswzing
yswzing 2013-06-19

[em68][em68][em68] 厉害!Perl 果然很强大!

【 在 rezilla 的大作中提到: 】

: perl不怎么熟练,献丑了 版主看见别笑话我

: $ cat b.txt

: (123, 434)

: ...................

Andor
珍惜 2013-06-19

sprintf

【 在 rezilla (@_0) 的大作中提到: 】

: perl不怎么熟练,献丑了 版主看见别笑话我

: $ cat b.txt

: (123, 434)

: (222, 2)

: $ perl -pi.bak -e 's#\(([0-9.]*), ([0-9.]*)\)#"(" . $1 / 0.7. ", " . $2 / 0.7. ")"#ge' b.txt

: $ cat b.txt

: (175.714285714286, 620)

: (317.142857142857, 2.85714285714286)

: $ cat b.txt.bak

: (123, 434)

: (222, 2)

: 要控制精度的话可能得用printf,不过在eval里用会把返回值也打出来,不知道怎么去。。。

rezilla
@_0 2013-06-19

thx 原来如此,都没用过这个。。。汗

学习了

【 在 Andor (珍惜) 的大作中提到: 】

: sprintf

flw
帅五进九 2013-06-20

你就大大方方用 s{}{} 不比你用 s### 可读性好啊。

perl -pi.bak -e 's{\d+}{int($&/0.7+0.5)}ge' b.txt

这样可好?

【 在 rezilla (@_0) 的大作中提到: 】

: perl不怎么熟练,献丑了 版主看见别笑话我

: $ cat b.txt

: (123, 434)

: (222, 2)

: $ perl -pi.bak -e 's#\(([0-9.]*), ([0-9.]*)\)#"(" . $1 / 0.7. ", " . $2 / 0.7. ")"#ge' b.txt

: $ cat b.txt

: (175.714285714286, 620)

: (317.142857142857, 2.85714285714286)

: $ cat b.txt.bak

: (123, 434)

: (222, 2)

: 要控制精度的话可能得用printf,不过在eval里用会把返回值也打出来,不知道怎么去。。。

rezilla
@_0 2013-06-20

{}{}确实看起来更舒服 版大批评的是 哈哈

看楼主的意思好像除了括号内别处也可能有不需要匹配的数字,所以才用了分组捕获

【 在 flw (还没想好) 的大作中提到: 】

: 你就大大方方用 s{}{} 不比你用 s### 可读性好啊。

: perl -pi.bak -e 's{\d+}{int($&/0.7+0.5)}ge' b.txt

: 这样可好?

: ...................

redleaves
红叶飘飘 2013-06-20

vim中运算只能对整数操作,不支持浮点运算。

可以先乘以10再除以7。

【 在 yswzing (yswzing) 的大作中提到: 】

: 标  题: 如何将文件中的所有数值都除以某一个数

: 发信站: 水木社区 (Wed Jun 19 11:49:20 2013), 站内

: 如何实现这样的需求,将文件中的所有形如 (x, y) 的串替换成 (x', y'),其中:

: 1. x, y 都是 NNNN.NNNN 或 NNNN 的数值;

: 2. x' = x/0.7, y' = y/0.7;

: 3. 一行中可能有多个 (x, y) 组,个数不确定,每行的格式不一致;

: vim, sed, awk 都有什么好的解决方法?因为文件很大,最好是可以用 sed/awk 实现。

: 初步的想法是用 s 命令,比如 s_(\([0-9.]*\), \([0-9.]*\))_(\1/0.7, \2/0.7)_g,但是不行,\1/0.7 没有被计算成数值,而是被当作字符串直接插入进去了。

: --

rezilla
@_0 2013-06-20

可以的,不过得用printf转一下

:h E806

【 在 redleaves (红叶飘飘) 的大作中提到: 】

: vim中运算只能对整数操作,不支持浮点运算。

: 可以先乘以10再除以7。