使用Perl计算文件中科学数字的数量


10

如何计算文件中科学数字的数量?该文件还有几行标题,需要跳过。

文件内容的一部分在下面。

FileHeaderLine1
FileHeaderLine2
FileHeaderLine3
FileHeaderLine4
2.91999996E-001 2.97030300E-001 3.02060604E-001 3.07090908E-001 3.12121212E-001 3.17151517E-001
3.22181821E-001 3.27212125E-001 3.32242429E-001 3.37272733E-001 3.42303038E-001 3.47333342E-001
3.52363646E-001 3.57393950E-001 3.62424254E-001 3.67454559E-001 3.72484863E-001 3.77515137E-001
3.82545441E-001 3.87575746E-001 3.92606050E-001 3.97636354E-001 4.02666658E-001 4.07696962E-001
4.12727267E-001 4.17757571E-001 4.22787875E-001 4.27818179E-001 4.32848483E-001 4.37878788E-001
4.42909092E-001 4.47939396E-001 4.52969700E-001

那么,如何跳过上面示例的前四行并计算文件中科学数字的数量?

Answers:


14

使用核心模块Scalar::Util,您可以执行以下操作:

$ perl -MScalar::Util=looks_like_number -anle '
    $count += grep { looks_like_number($_) } @F;
    END { print $count }
' file
33

有关更多信息looks_like_number,请参见perldoc perlapi


+1很酷,我不知道looks_like_number
钢铁司机

7

使用GNU grep

您可以使用grepPCRE工具来执行此操作。顺便说一下,在Perl中也可以使用相同的模式:

$ grep -oP '\d+E[-+]?\d+' file.txt  | wc -l
33

您还可以wc -w用来计数单词,我是在上面计算行数,但是grep返回的结果是一行上的一个匹配项,因此在这种情况下这并不重要。

使用Perl

对于Perl,您可以使用这种衬板:

$ perl -lane '$c += grep /\d+E[-+]?\d+/, @F; END { print $c; }' file.txt 
33

参考文献


@StephaneChazelas-感谢您的编辑。抱歉,我只在GNU系统上工作过,所以总是会忘记这一点。我会尽量不要犯这个错误。
slm

4

egrep 将工作:

egrep "[0-9].[0-9]E-[0-9]" YourFile | wc -w

更新:

如果一行恰好同时包含数字和其他字符串,我们可以使用它awk来解决问题:

awk -F' ' '{for(i=1;i<=NF;i++)if(!(i%1))$i=$i "\n"}1' YourFile | egrep "[0-9].[0-9]E-[0-9]" | wc -w ( or wc -l )

如果一行恰好同时包含数字和其他字符串,这将导致错误的结果。上面使用grep的-o选项仅输出匹配项的答案更为正确。
2014年

我之前不知道-oPslm答案中提到的选项,但已使用awk@Johnny 解决了我的问题
Networker

3

假设第四行之后只有科学数字,则可以执行以下操作。

tail -n +5 filename | wc - w

对于您提供的输入,运行以上命令后输出为33


3

如果您只需要计算perl标头行后面的空格分隔字段的数量,我认为您可以这样做

perl -lane '$sum += $#F+1 if $. > 4; END{print $sum}' file

如果您真的只需要计算科学格式的数字,则一种方法可能是根据合适的正则表达式搜索和替换数字,然后计算替换的数量(当您将perl替换表达式绑定到变量时,它会返回替换的数量。 )

perl -lane '$sum += s/[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?//g if $. > 4; END{print $sum}' file

2

一切都取决于您实际要考虑的科学数字,可以期望输入包含的内容以及可以接受的位置,以便在输入中找到这些数字。

例如,在:

That's inferior to the LK2E2000 model.

我可以找到0或2(inf和2E2000)或3(inf,2E200、0)数字(或取其极值,查找构成有效数字的所有字符序列:17(inf,2、2E2, 2E20、2E200、2E200、2E2000、2、20、200、2000、0、00、000、0、00、0))。

如果您知道输入的X.XXXXXXXXE-XXX中只有数字,并且它们使用自己的单词,那么在整个单词中查找这样的单词可能会更安全:

tr -s '[[:blank:]]' '[\n*]' | LC_ALL=C grep -xEc '[0-9]\.[0-9]{8}E-[0-9]{3}'

此处的想法是每行获得一个单词,并使整个行(-x)与所需的模式匹配。要允许任何科学的记号(-1.2e + 1234 ...,只要有eE),可以将模式更改为:

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])[eE][-+]?[0-9]+

或者使该e...部分为可选,以允许各种十进制浮点数:

[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9])([eE][-+]?[0-9]+)?

所有这些都为您的特定输入提供了相同的答案,但是有区别的地方是输入偏离了示例中显示的严格模式。

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.