我有一个要修改的文件。有 100 个文件存在相同问题。输入文件如下
sample1 100A total 1 1000
sample2 100A total 1 5584
sample3 100A total 1 8125
sample4 100A total 1 59
sample1 . year 1 1000
sample1 . week1 20 1001
sample1 . week2 50 1001
sample2 . year 1 5584
sample2 . week1 20 5585
sample2 . week2 100 5585
sample3 . year 1 8125
sample3 . week1 55 8126
sample3 . week2 100 8126
sample4 . year 1 59
sample4 . week1 10 59
sample4 . week2 8 59
在上面的文件中,第三列中的“总计”是查找表,其最大值不应超过下面各个样本的任何行。
例如,“sample1”的最大值为 1000,但第三列中的“week1”和“week2”的最大值为“1001”。我发现这种情况仅发生在“week1 和 week2”的几行中,并且始终只比最大值大 1。 “week1”和“week2”行的输出应更新为最大值“1000”。下面的示例输出
sample1 100A total 1 1000
sample2 100A total 1 5584
sample3 100A total 1 8125
sample4 100A total 1 59
sample1 . year 1 1000
sample1 . week1 20 1000
sample1 . week2 50 1000
sample2 . year 1 5584
sample2 . week1 20 5584
sample2 . week2 100 5584
sample3 . year 1 8125
sample3 . week1 55 8125
sample3 . week2 100 8125
sample4 . year 1 59
sample4 . week1 10 59
sample4 . week2 8 59
请为我提供指导,告诉我应该如何进行。我是一名初学者程序员,希望学习。感谢您的帮助
答案1
使用乐(以前称为 Perl_6)
~$ raku -e 'my @a = slurp.split("\n\n", 2); print @a[0] ~ "\n\n";
my %h; for @a.[0].lines() { \%h.push: .words.[0,4] };
for @a[1].lines {
S/^ (\S+)(.* \s)(\S+) $/{"$0$1"}{ %h{$0} < $2 ?? "%h{$0}" !! "$2" }/.put };' file.txt
Raku 是 Perl 家族中的一种编程语言,因此它的语法无疑是“Perl 式的”。上面我们将slurp
文件一次性全部放入内存,2
在第一段之后将文件分成几个部分。该数据存储在@a
数组中。包含参考值 ( ) 的第一部分@a[0]
将立即print
编辑。
%h
然后声明一个哈希值。我们@a[0]
使用for
...迭代顶部摘要段落 ( ) lines
。这里,每一行都被分成空格分隔的words
,.[0,4]
第一/第五列作为引用键/值对push
添加到哈希中。%h
文件的其余部分 ( ) 通过使用...@a[1]
进行迭代,这意味着我们可以分析/修改块中的每一行。使用 Raku 的非破坏性替换习惯用法返回修改后的字符串,我们将输入分为第一(键)列、中间列和最终(值)列。for
lines
S///
$0
$1
$2
在替换中,我们只需{"$0$1"}
按原样打印即可。然而,对于最后一列,我们可以在大括号内运行代码:使用 Raku 的三元运算符测试 ??
真的 !!
错误的如果它小于,我们返回%h{$0}
(key
的关联) ,否则返回原始值 ( ) 。value
$2
$2
输入示例:
sample1 100A total 1 1000
sample2 100A total 1 5584
sample3 100A total 1 8125
sample4 100A total 1 59
sample1 . year 1 1000
sample1 . week1 20 1001
sample1 . week2 50 1001
sample2 . year 1 5584
sample2 . week1 20 5585
sample2 . week2 100 5585
sample3 . year 1 8125
sample3 . week1 55 8126
sample3 . week2 100 8126
sample4 . year 1 59
sample4 . week1 10 59
sample4 . week2 8 59
示例输出:
sample1 100A total 1 1000
sample2 100A total 1 5584
sample3 100A total 1 8125
sample4 100A total 1 59
sample1 . year 1 1000
sample1 . week1 20 1000
sample1 . week2 50 1000
sample2 . year 1 5584
sample2 . week1 20 5584
sample2 . week2 100 5584
sample3 . year 1 8125
sample3 . week1 55 8125
sample3 . week2 100 8125
sample4 . year 1 59
sample4 . week1 10 59
sample4 . week2 8 59
最后,查看中间数据结构通常会很有启发,因此%h
哈希如下所示(使用.say for %h.sort;
);
sample1 => 1000
sample2 => 5584
sample3 => 8125
sample4 => 59
https://docs.raku.org/syntax/S%2F%2F%2F%20非破坏性%20替换
https://docs.raku.org/language/operators#infix_??_!!
https://docs.raku.org/language/regexes
https://raku.org
答案2
一个简单的 Awk 语句:
awk -v OFS='\t' '$3 == "total" {maxval[$1] = $5} $1 in maxval && $5 > maxval[$1] {$5 = maxval[$1]} {print}' input.txt
添加了一些换行符:
awk -v OFS='\t' '
$3 == "total" {
maxval[$1] = $5
}
$1 in maxval && $5 > maxval[$1] {
$5 = maxval[$1]
}
{print}' input.txt
解释:
首先,根据输入文件中的可变间距,我假设它是原始文本中的制表符分隔文本;看来是的。
默认情况下,Awk 将根据任意数量的相邻制表符或空格来解析以分隔字段。对于这个文件来说这很好。
但我们希望输出保持整齐对齐,默认情况下,如果我们更改某些字段值,Awk 会将该行的所有字段分隔符转换为单个空格。因此,我们将输出字段分隔符(OFS)设置为等于制表符,并带有-v
用于设置变量的标志。
对于第三个字段是字符串“total”的行,我们将最大值保存在关联数组中(有时称为“散列”,具体取决于您最熟悉的编程语言)。
如果该行的第一个字段存在于关联数组中,并且第五个字段是更大比存储在数组中的值作为该键的最大值,然后我们更改当前行的第五个字段。
然后我们打印当前行,无论是否修改。
提供的输入的输出:
sample1 100A total 1 1000
sample2 100A total 1 5584
sample3 100A total 1 8125
sample4 100A total 1 59
sample1 . year 1 1000
sample1 . week1 20 1000
sample1 . week2 50 1000
sample2 . year 1 5584
sample2 . week1 20 5584
sample2 . week2 100 5584
sample3 . year 1 8125
sample3 . week1 55 8125
sample3 . week2 100 8125
sample4 . year 1 59
sample4 . week1 10 59
sample4 . week2 8 59