不使用“ e”来操纵科学格式


8

我正在尝试处理一个包含以科学计数法表示的数字但没有e符号(即1.2e+3写为)的文件1.2+3

我想到的最简单的方法awk是使用函数替换+e+gsub并在新文件中进行计算。减号情况也是如此。因此,可以使用以下命令完成简单的修复

awk '{gsub("+", "e+", $1); print $1, $2, $3, $4, $5}' file_in

并在所有列中执行相同操作。

但是,该文件还包含负数,这使事情变得更加复杂。可以看到一个示例文件

 1.056000+0 5.000000-1 2.454400-3 2.914800-2 8.141500-6
 2.043430+1 5.000000-1 2.750500-3 2.698100-2-2.034300-4
 3.829842+1 5.000000-1 1.969923-2 2.211364-2 9.499900-6
 4.168521+1 5.000000-1 1.601262-2 3.030919-2-3.372000-6
 6.661784+1 5.000000-1 5.250575-2 3.443669-2 2.585500-5
 7.278104+1 5.000000-1 2.137055-2 2.601701-2 8.999800-5
 9.077287+1 5.000000-1 1.320498-2 2.961020-2-1.011600-5
 9.248130+1 5.000000-1 3.069610-3 2.786329-2-6.317000-5
 1.049935+2 5.000000-1 4.218794-2 3.321955-2-5.097000-6
 1.216283+2 5.000000-1 1.432105-2 3.077165-2 4.300300-5

关于如何使用此类文件进行操作和计算的任何想法?


2
您想如何使用2.698100e-2-2.034300e-4这样的格式进行计算?
ctac_

3
看起来好像应该将其解析为固定宽度的列数据。列之间的明显空白只是数字格式的假象,它显示带前导空格而不是加号的正值。
Ilmari Karonen

Answers:


14

这个输出正确吗?

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2-2.034300e-4
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2-3.372000e-6
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2-1.011600e-5
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2-6.317000e-5
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2-5.097000e-6
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5

码:

perl -lne 's/(\.\d+)(\+|\-)/\1e\2/g; print' sample

说明:

  • -lne 注意行尾,处理每个输入行,执行下面的代码

  • s/(\.\d+)(\+|\-)/\1e\2/g

    • 替代(s
    • (.\d+)(\+|\-) 查找两组(点和数字)和(加号或减号)
    • \1e\2用第一组代替它们,e然后第二组
    • g 全局-不要在每行的第一个替换处停止,而是处理所有可能的匹配
  • print 打印线

  • sample 输入文件

如果丢失,这会增加空间。实际上,无论如何,它都会在数字之间放置空格。就是 如果在某些情况下有两个空格,则输出中将只有一个空格。

perl -lne 's/(\.\d+)(\+|\-)(\d+)(\s*)/\1e\2\3 /g; print' sample

大部分与前一个相似。新的东西是(\d+)组nr 3和(\s*)组nr4 *。这里表示可选。在替换\4中,使用no 。而是有一个空间。

输出是这样的:

 1.056000e+0 5.000000e-1 2.454400e-3 2.914800e-2 8.141500e-6 
 2.043430e+1 5.000000e-1 2.750500e-3 2.698100e-2 -2.034300e-4 
 3.829842e+1 5.000000e-1 1.969923e-2 2.211364e-2 9.499900e-6 
 4.168521e+1 5.000000e-1 1.601262e-2 3.030919e-2 -3.372000e-6 
 6.661784e+1 5.000000e-1 5.250575e-2 3.443669e-2 2.585500e-5 
 7.278104e+1 5.000000e-1 2.137055e-2 2.601701e-2 8.999800e-5 
 9.077287e+1 5.000000e-1 1.320498e-2 2.961020e-2 -1.011600e-5 
 9.248130e+1 5.000000e-1 3.069610e-3 2.786329e-2 -6.317000e-5 
 1.049935e+2 5.000000e-1 4.218794e-2 3.321955e-2 -5.097000e-6 
 1.216283e+2 5.000000e-1 1.432105e-2 3.077165e-2 4.300300e-5 

非常感谢您的回答!是的,这似乎是正确的!您能解释一下自己做了什么,以备将来参考吗?
Thanos

是否还可以将前一列($ 5 $)与前一列隔开一个空格?
Thanos

你太完美了!非常感谢您的帮助!
塔诺斯

@Thanos查看更新。并注意.在第一组中我之前添加了一个反斜杠。这是对的。如果没有此反斜杠,则该点将不表示文字点。

2

您也可以使用sed,例如:

<infile sed -E 's/([0-9])([+-])([0-9])/\1e\2\3/g' | awk '{ print $1 + 0 }'

但是,这没有考虑到OP列表中的列有时没有分开的情况。这是一种具有适当精度的解决方法:

<infile sed -E 's/.{11}/& /g'       |
sed -E 's/([0-9])([+-])/\1e\2/g'    |
gawk '{ print $1 + 0 }' OFMT='%.7g'

输出:

1.056
20.4343
38.29842
41.68521
66.61784
72.78104
90.77287
92.4813
104.9935
121.6283

从数字这消除了分辨率,而且我不知道什么时候负值就像是在问题的例子旁边另一个它将工作2.698100-2-2.034300-4

@pipe:你是对的,我错过了那个细节。我通过增加空间来添加解决方法。Wrt。精度,我使用的OFMT变量来设定AWK的精度相同的作为输入的
托尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.