![如何打印正则表达式匹配的一部分以及所有其他匹配的列表](https://linux22.com/image/210754/%E5%A6%82%E4%BD%95%E6%89%93%E5%8D%B0%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8C%B9%E9%85%8D%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%E4%BB%A5%E5%8F%8A%E6%89%80%E6%9C%89%E5%85%B6%E4%BB%96%E5%8C%B9%E9%85%8D%E7%9A%84%E5%88%97%E8%A1%A8.png)
我正在总结一些测试结果,所以我有这种类型的文本:
FAILED src/path/to/code.test.js
Test Suite
答案1
这更像是一项工作perl
:
perl -lne '
if (/^\h*at\h.*?\((src.*?\.test\.js):(\d+:\d+)\)/) {
$total{$1}++;
$lines{$1}->{$2}++
}
END {
for $file (sort {$total{$b} <=> $total{$a}} keys %total) {
my $l = $lines{$file};
print "$total{$file} $file (" .
join(", ", map "$l->{$_} - $_", sort {$l->{$b} <=> $l->{$a}} keys %$l) . ")"
}
}'
请注意,*?
由于 的非贪婪版本*
是 perl 正则表达式运算符。我知道只有一种sed
实现支持它(除了-r
非标准的等效项之外-E
),但我怀疑这就是您正在使用的实现。这就是 ast-open,sed
据我所知,默认情况下任何系统都不会提供这种工具,甚至包括已知包含或至少考虑包含 ksh93 以外的 ast-open 工具的 Illumos 也不包含在内。在sed
(引入该选项的那个-r
)的 GNU 实现中, .*?
is ?
(0 或 1 个前面的原子) 应用于(0 个或多个字符),因此与and (0 或 1 个或多个字符).*
相同也一样。.*
.+?
.*
答案2
awk '/^[[:blank:]]*at.*\(src.*\.test\.js:[0-9]+:[0-9]+\)/{
split($0, tmp, /[)(:]/) ## Assuming there is no ), ( and : in the filePath
fileCnt [tmp[2]]++
fileErrs[tmp[2], tmp[3]":"tmp[4]]++
}
END{
for (fileName in fileCnt){
sep=""
printf ("%s %s (", fileCnt[fileName], fileName)
for(file in fileErrs){
split(file, tmp, SUBSEP)
if(fileName==tmp[1]){
printf("%s - %s", sep fileErrs[file], tmp[2])
sep=", "
}
}
print ")"
}
}' infile ## or infiles*
关联的数组fileCnt
仅保留文件名的计数;数组的键是文件的名称,值是它们看到的次数。关联的
数组fileErrs
保存每个文件名的错误计数;其中键是 fileName+errNums 的组合。
在 END 块,我们正在处理文件数数组并打印文件计数fileCnt[fileName]
,然后打印文件名本身fileName
;然后我们正在处理文件错误数组并分割关键部分,然后我们将第一部分与文件名进行比较,以查找每个文件的单独错误。
答案3
使用乐(以前称为 Perl_6)
~$ raku -ne 'state %h; state $i; ++$i; \
if m/ ^ \h* at \h .*? "(" ~ ")" [(src .*? \.test \.js) \: (\d+ \: \d+)] / \
-> { %h.push: $0 => $i ~"|"~ $1 }; END .say for %h;' file
-ne
简而言之,代码使用(非自动打印)命令行标志在输入文件上逐行运行。给出了一个哈希值%h
。$i
声明了一个迭代器。对于每一行,$i
迭代器都会递增。if
与正则表达式匹配的条件测试相似但不相同到 @Stephane_Chazelas 发布的 Perl5 代码。然而,这个 Raku 正则表达式使用了一个很好的(较新的)功能——Raku 的~
嵌套数据结构波浪线语法:"(" ~ ")" [ … ]
。 Raku 正则表达式将捕获路径$0
并将冒号分隔的数字捕获到$1
。
当找到(逐行)匹配时,它会被push
添加到%h
散列中:($0
路径)用作键,而值则成为使用代码(使用~
)连接到捕获的数字部分的行号: 。由于散列中不能存在重复的键,因此每个键(即路径)会累积不同的值。在读取行的最后,输出哈希值。$1
$i ~"\t"~ $1
END
%h
输入示例:
#See above. OP's original file was concatenated 5 times,
#one record was altered (path and digits).
输出示例 (1):
src/path/to/code.test.js => [13|31:415 27|31:415 55|31:415 69|31:415]
src/path/to/othercode.test.js => 41|32:416
要获取计数的前导列,请将后面的代码替换END
为以下内容:
for %h.kv -> $k,$v {say $v.elems, "\t", $k => $v};
输出示例 (2):
4 src/path/to/code.test.js => [13|31:415 27|31:415 55|31:415 69|31:415]
1 src/path/to/othercode.test.js => 41|32:416
[注意:在涉及哈希值的情况下,通常say
会生成箭头分隔的输出。在上面,您只需将最终命令更改为]key => value
即可获得制表符分隔的键值输出。say
put
https://docs.raku.org/language/regexes#Tilde_for_nesting_structs
https://docs.raku.org/language/hashmap
https://raku.org