匹配一个浮点数并乘以 100

Match a float and multiply by 100

我想从覆盖率报告中提取一个浮点数并将其乘以 100 以报告百分比。

我可以使用 sedgrep 匹配浮点数,然后使用 awk 相乘,但我想知道是否有更优雅的单一工具解决方案,也许仅 perlawk

该行看起来像这样:

<coverage line-rate="0.34869999999999995" branch-rate="0.2777" >

我目前的解决方案:

sed -n 's/^<coverage line-rate="\([0-9\.]*\)".*$//p' a.txt | awk '{print (100 * )}'
34.87

使用您显示的示例,请尝试执行以下 awk 程序。在 GNU awk.

中编写和测试
awk '
match([=10=],/coverage line-rate="([^"]*)"/,arr){
  printf("%0.2f\n",arr[1] * 100)
}
' Input_file

说明: 使用 awk 程序的 match 函数,在 match 函数中使用正则表达式coverage line-rate="([^"]*)" 匹配字符串 coverage line-rate=" 直到下一次出现 " 并将捕获组的值保存到数组 arr 中。然后使用 printf 打印值,其中使用 %0.2f\n 仅获取 2 个浮点数的值。

一种捕获数字并使用 Perl 处理它(如果匹配)的方法

perl -wnE'say 100 *  if /^<coverage line-rate="([0-9]*\.[0-9]*)"/' file

提取捕获和处理(相乘并打印)它们的另一种方法

perl -wnE'say 100 * $_ for /^<coverage line-rate="([0-9]*\.[0-9]*)"/' file

这使用匹配运算符 (/.../) 的 属性 到 return 列表上下文中的匹配项,由 for 循环提供,我们在其中然后处理匹配(在这种情况下只有一个),相乘并打印。当没有匹配项时,循环将没有要迭代的项目。

它们都处理一个文件,并且只打印匹配行的结果,就像问题中一样。在这两种情况下,如果需要特定的精度,可以将 say 替换为 printf ".2f\n", $x;(两位小数等)。


我不确定从 one-liner 中打印数字是否确实是最终需要,或者仅仅是为此目的的简化表示,但当然还有其他方法。

也可以通过匹配索引到列表中以提取捕获的模式

my $num = ( /^<coverage line-rate="([0-9]*\.[0-9]*)/ )[0];

然后检查(是否匹配)后处理,$num *= 100 if defined $num;

如果输入字符串需要更改,如问题中所做的那样,可能为了进一步的工作,达到特定的精度

# Keep four decimal places
s/^<coverage line-rate="([0-9]*\.[0-9]*).*/sprintf("%.4f", 100*)/e; 

或者如果精度无关紧要,可以留给解释器

s/^<coverage line-rate="([0-9]*\.[0-9]*).*/100*/e; 

在这两种情况下,/e 修饰符都会将替换部分作为代码进行评估,因此我们可以在那里进行一些处理。在第一种情况下,我使用 sprintf 来格式化替换字符串,而在另一种情况下,它只是相乘。


这里可能存在一个潜在的复杂问题,即需要保留多少位数字。如果它应该与原始数字相同,那么我们可能需要首先检测它有多少

use warnings;
use strict;
use feature 'say';

# Number is shortened for demonstration
my $str = shift // q(<coverage line-rate="0.348691" branch-rate="0.2777" >);

sub process_num {
    my ($num, $frac) = @_;

    $num *= 100;
    my $frac_len = length($frac) - 2;  # keeps same digits

    return sprintf "%.${frac_len}f", $num;
}

$str =~ s/^<coverage line-rate="([0-9]*\.([0-9]+)).*/process_num(, )/e;

say $str;

运行 这没有参数打印 34.8691 而不是带有 0.348691

的原始行

因此假设数字至少有小数部分。

使用"作为字段分隔符:

awk -F '"' '{print *100}' file

输出:

34.87

这是一个gnu-awk解决方案:

awk '/^<coverage /{
   print 100 * gensub(/.* line-rate="([0-9.]+)".*/, "\1", "1")}' file

34.87