【问题标题】:Awk/Sed/Perl - If two consecutive columns match two paterns, make a new row [closed]Awk/Sed/Perl - 如果两个连续的列匹配两个模式,则创建一个新行 [关闭]
【发布时间】:2016-02-13 16:45:28
【问题描述】:

我制作了一个 bash 脚本,它一直工作到今天。出于某种原因,可能是更新中的错误,数据开头有一个不会消失的空行... sed '/^$/d'。然而,“tail -n +2”确实使它消失并且脚本再次工作。由于该问题只发生过一次,因此我不愿将尾行添加到我的代码中,因为如果该错误不再发生,它可能会擦除数据。简而言之,我正在寻找健全性检查。

我在网络上找不到任何内容,其中包含验证最后 2 列数据作为下一行开始条件的示例。

我在这里发布问题,经过编辑并希望更清楚,因为我不是在寻找一个计算列和行的解决方案,而是一个将验证最后两列格式为“$1.00 $44, 89987”。

即倒数第二行($NF-1)为带美元符号和小数的货币格式,最后一列($NF)为带美元符号的货币格式,没有小数,有时是逗号。

在此编辑之前发布的解决方案,请使用给出的示例。一些解决方案将四列的数量作为条件,并假设数据从一开始就正确格式化(正如我在第一段中指出的那样,开头没有空行)。

在我的脚本中,我将每一列拆分为单独的行,然后将每 4 行重新组合为一行。类似于以下一些解决方案。对于在此编辑之前缺乏沟通,我深表歉意,并感谢发布它们的人的解决方案。

我的原始代码是一个很长的单行代码,有许多管道,它将一个文件格式化为所需的格式,该文件在行中包含大量数据(开头没有列)。 (它使用存储的 bash 变量作为昨天的日期):

cat BiggestPayouts |perl -lape 's/\s+//sg'|sed 's/"//g'|sed '/^$/d'|awk 'length>2'|awk 'NR%4{printf $0" ";next;}1'|awk -v yest=$yest '{print yest"@"$1"@"$2"@"$3"@"$4}' >> BigPayouts.csv

但是,如前所述,我正在寻找一个 if 语句来验证最后两列数据作为下一行的条件。

也许,如果有人能指出如何使用 (awk/sed/perl/regex) 来查找我上面描述的货币格式的“任意两个连续列”(带小数和美元的美元符号符号,逗号,不带小数),我可以将所有数据放入一行,然后在每次找到条件时让代码将该行分成新行。

类似:

James Invest $1.00 $26,443 Charles Spent $0.20 $18,119 Sam Expense $0.50 $16,049 James Shared $0.50 $6,373  Charles Gave $1.00 $6,235 Sam Burned $1.00 $5,585     

结果应该有最后两列作为货币,然后是一个新行。这样……

James Invest $1.00 $26,443 
Charles Spent $0.20 $18,119 
Sam Expense $0.50 $16,049 
James Shared $0.50 $6,373 
Charles Gave $1.00 $6,235 
Sam Burned $1.00 $5,585 

【问题讨论】:

  • 在此处发布您的挑战之前先尝试一下!如果您遇到困难,请edit 您的问题向我们展示您的尝试。
  • 是否可以先删除所有\n\r 字符,然后将每四个空白替换为\n?它认为无需任何awk 代码即可完成
  • 这可行,并且已经在我的脚本中使用。不幸的是,今天的数据出现了错误,现在我正在寻找一种方法来在保存之前对数据格式进行完整性检查。
  • “这会起作用,并且已经在我的脚本中使用了” 如果你有显示你当前的代码会更好尝试自己解决这个问题
  • 高尔夫尝试perl -pE 'chomp if y|$|| <3; say " $1" if s/^(\$\S+) //' file

标签: linux perl if-statement awk sed


【解决方案1】:

如果您的第一个想法是直接寻求帮助而不是尝试自己解决问题,那是可耻的想法。遗憾的是,Stack Overflow 上的贡献者被提供的经验点鼓励来为您解决问题,而不是帮助您找到自己的解决方案。不过,既然这里已经有好几种解决方案了,那我还是自己加一个吧

该程序创建一个匹配货币值的正则表达式模式$amt,并用换行符替换出现两次金额之后和非金额之前的任何空格

use strict;
use warnings 'all';
use v5.10;

my $data = do {
    local $/;
    <DATA>;
};

my $amt = qr/\$[\d.,]+/;

$data =~ s/\s+/ /g;
$data =~ s/ $amt \s+ $amt \K \s+ (?= [^\$\s] ) /\n/gx;

say $data;

__DATA__
James Invest $1.00
$26,443 Charles Spent $0.20
$18,119 Sam Expense $0.50
$16,049 James Shared $0.50 $6,373
Charles Gave $1.00
$6,235 Sam Burned $1.00
$5,585

输出

James Invest $1.00 $26,443
Charles Spent $0.20 $18,119
Sam Expense $0.50 $16,049
James Shared $0.50 $6,373
Charles Gave $1.00 $6,235
Sam Burned $1.00 $5,585 

更新

或者,如果只是一次打印四个字段的值,那么解决方案要简单得多

use strict;
use warnings 'all';
use v5.10;

my @data;
while ( <DATA> ) {
    push @data, split;
    while ( @data >= 4 ) {
        my @row = splice @data, 0, 4;
        print "@row\n";
    }
}

print "@data\n" if @data;

__DATA__
James Invest $1.00
$26,443 Charles Spent $0.20
$18,119 Sam Expense $0.50
$16,049 James Shared $0.50 $6,373
Charles Gave $1.00
$6,235 Sam Burned $1.00
$5,585

输出与我原来的解决方案相同

【讨论】:

    【解决方案2】:

    另一个awk解决方案,打印"\n"每四条记录

    awk -vRS="[ \n]+" '
        NR%4!=1{printf OFS}
        {printf "%s",$0;}
        NR%4==0{printf "\n"}' file
    

    你明白了,

    詹姆斯投资 $1.00 $26,443 查尔斯花费 0.20 美元 18,119 美元 山姆费用 0.50 美元 16,049 美元 詹姆斯分享 $0.50 $6,373 查尔斯给了 $1.00 $6,235 山姆烧了 1.00 美元 5,585 美元

    【讨论】:

      【解决方案3】:

      Perl 解决方案:

      perl -lane 'chomp;
                  push @B, @F;
                  print join " ", splice @B, 0, 4 while @B > 3
                 ' input_file
      
      • chomp 删除尾随的换行符。
      • 数组@B 用作缓冲区。
      • -a 将空格上的输入拆分为 @F 数组
      • -lprint 添加一个换行符

      【讨论】:

        【解决方案4】:
        awk -vRS= '{for(i=1;i<=NF;i++)if(i%4){printf $i" "}else{print $i}}' file
        

        【讨论】:

          猜你喜欢
          • 2011-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多