匹配一个浮点数并乘以 100
Match a float and multiply by 100
我想从覆盖率报告中提取一个浮点数并将其乘以 100 以报告百分比。
我可以使用 sed
或 grep
匹配浮点数,然后使用 awk
相乘,但我想知道是否有更优雅的单一工具解决方案,也许仅 perl
或 awk
?
该行看起来像这样:
<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
我想从覆盖率报告中提取一个浮点数并将其乘以 100 以报告百分比。
我可以使用 sed
或 grep
匹配浮点数,然后使用 awk
相乘,但我想知道是否有更优雅的单一工具解决方案,也许仅 perl
或 awk
?
该行看起来像这样:
<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