Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 为制表符分隔文件中的每列执行不同的正则表达式_Linux_Perl_Bash_Unix - Fatal编程技术网

Linux 为制表符分隔文件中的每列执行不同的正则表达式

Linux 为制表符分隔文件中的每列执行不同的正则表达式,linux,perl,bash,unix,Linux,Perl,Bash,Unix,我发现自己在大约8年的时间里第一次编写PERL,在一些本应简单的事情上遇到了困难。这是一个基本前提: 包含大约100个字段的文件,其中10个字段的数据不正确(O为0) 我正在尝试编写程序来拆分字段,然后允许我在字段a上运行正则表达式,以将0替换为O,但不将列C的0替换为O,因此我还有一个额外的问题,例如,可能需要为列E运行备用正则表达式 我能够通过/t拆分记录中的所有字段。我在格式化我的命令时遇到了一个问题,我需要遍历每个字段并根据它所在的字段运行特定的正则表达式 任何帮助都将不胜感激,如果您能

我发现自己在大约8年的时间里第一次编写PERL,在一些本应简单的事情上遇到了困难。这是一个基本前提:

包含大约100个字段的文件,其中10个字段的数据不正确(O为0)

我正在尝试编写程序来拆分字段,然后允许我在字段a上运行正则表达式,以将0替换为O,但不将列C的0替换为O,因此我还有一个额外的问题,例如,可能需要为列E运行备用正则表达式

我能够通过/t拆分记录中的所有字段。我在格式化我的命令时遇到了一个问题,我需要遍历每个字段并根据它所在的字段运行特定的正则表达式


任何帮助都将不胜感激,如果您能解决问题,我将向您支付10美元,购买您选择的饮料。

这里有一种使用
GNU awk
的方法。只需将列名添加到
BEGIN
块中的数组中即可。在下面的示例中,只修改A、C和E列。运行方式如下:

awk -f script.awk file
script.awk的内容

BEGIN {
    FS=OFS="\t"

    a["A"]
    a["C"]
    a["E"]
}

{
    for (i=1;i<=NF;i++) {

        if ($i in a && NR==1) {
            b[i]
        }

        else if (i in b) {
            $i = gensub(/(^|[^0-9])0([^0-9]|$)/,"\\1o\\2", "g", $i)
        }
    }
}1
或者,这里有一个班轮:

awk 'BEGIN { FS=OFS="\t"; a["A"]; a["C"]; a["E"] } { for (i=1;i<=NF;i++) { if ($i in a && NR==1) b[i]; else if (i in b) $i = gensub(/(^|[^0-9])0([^0-9]|$)/,"\\1o\\2", "g", $i) } }1' file

awk'BEGIN{FS=OFS=“\t”;a[“a”];a[“C”];a[“E”}{for(i=1;i这里有一种使用
GNU awk
的方法。只需将列名添加到
BEGIN
块中的数组中。在下面的示例中,只修改列a、C和E。按如下方式运行:

awk -f script.awk file
script.awk的内容

BEGIN {
    FS=OFS="\t"

    a["A"]
    a["C"]
    a["E"]
}

{
    for (i=1;i<=NF;i++) {

        if ($i in a && NR==1) {
            b[i]
        }

        else if (i in b) {
            $i = gensub(/(^|[^0-9])0([^0-9]|$)/,"\\1o\\2", "g", $i)
        }
    }
}1
或者,这里有一个班轮:

awk 'BEGIN { FS=OFS="\t"; a["A"]; a["C"]; a["E"] } { for (i=1;i<=NF;i++) { if ($i in a && NR==1) b[i]; else if (i in b) $i = gensub(/(^|[^0-9])0([^0-9]|$)/,"\\1o\\2", "g", $i) } }1' file

awk'BEGIN{FS=OFS=“\t”;a[“a”];a[“C”];a[“E”]}{for(i=1;i创建一个子程序数组,类似于:

my @fixer;
$fixer[0] = sub { $_[0] =~ s/0/o/; };
my @fields = split /\t/, $input;
for (my $i = 0; $i <= $#fields; $i++) {
   $fixer[$i]->($fields[$i]) if defined $fixer[$i];
}
my@fixer;
$fixer[0]=sub{$[0]=~s/0/o/;};
my@fields=split/\t/,$input;
对于(我的$i=0;$i($fields[$i]),如果定义了$fixer[$i];
}

创建一系列子例程,例如:

my @fixer;
$fixer[0] = sub { $_[0] =~ s/0/o/; };
my @fields = split /\t/, $input;
for (my $i = 0; $i <= $#fields; $i++) {
   $fixer[$i]->($fields[$i]) if defined $fixer[$i];
}
my@fixer;
$fixer[0]=sub{$[0]=~s/0/o/;};
my@fields=split/\t/,$input;
对于(我的$i=0;$i($fields[$i]),如果定义了$fixer[$i];
}

使用csv解析器(如)并不复杂。类似这样的方法可能就足够了:

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol         => $/,
});
while (my $row = $csv->getline(*DATA)) {
    tr/0/o/ for @{$row}[0, 1, 3];            # replace in cols A, B and D
    s/(?<!\d)0(?!\d)/o/g for @{$row}[4];     # replace in col E
    $csv->print(*STDOUT, $row);              # print the result
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456
请注意,我用一个简单的正则表达式而不是音译(全局替换)来处理您的混合字符串(列E),它只是不替换数字旁边的零,而数字旁边的零对于某些数字将失败,例如
20.0
0

更新:

A       B       C       D       E       F
brown   red     1278076 orange  "20 trout"      123
Green   orange  90876   Yellow  "18 Salmon"     456
如果您想基于列名而不是位置进行替换,事情会变得更复杂。但是,
Text::CSV
可以处理它

use strict;
use warnings;
use Text::CSV;

my @pure_text   = qw(A B D);
my @mixed       = qw(E);

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol     => $/,
});

my $cols = $csv->getline(*DATA);              # read column names
$csv->print(*STDOUT, $cols);
$csv->column_names($cols);                    # set column names

while (my $row = $csv->getline_hr(*DATA)) {   # hash ref instead of array ref
    tr/0/o/ for @{$row}{@pure_text};          # substitution on hash slice
    s/(?<!\d)0(?!\d)/o/g for @{$row}{@mixed};
    my @row = @{$row}{@$cols};                # make temp array for printing
    $csv->print(*STDOUT, \@row);
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456

使用csv解析器(如)并不复杂。类似这样的方法可能就足够了:

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol         => $/,
});
while (my $row = $csv->getline(*DATA)) {
    tr/0/o/ for @{$row}[0, 1, 3];            # replace in cols A, B and D
    s/(?<!\d)0(?!\d)/o/g for @{$row}[4];     # replace in col E
    $csv->print(*STDOUT, $row);              # print the result
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456
请注意,我用一个简单的正则表达式而不是音译(全局替换)来处理您的混合字符串(列E),它只是不替换数字旁边的零,而数字旁边的零对于某些数字将失败,例如
20.0
0

更新:

A       B       C       D       E       F
brown   red     1278076 orange  "20 trout"      123
Green   orange  90876   Yellow  "18 Salmon"     456
如果您想基于列名而不是位置进行替换,事情会变得更复杂。但是,
Text::CSV
可以处理它

use strict;
use warnings;
use Text::CSV;

my @pure_text   = qw(A B D);
my @mixed       = qw(E);

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol     => $/,
});

my $cols = $csv->getline(*DATA);              # read column names
$csv->print(*STDOUT, $cols);
$csv->column_names($cols);                    # set column names

while (my $row = $csv->getline_hr(*DATA)) {   # hash ref instead of array ref
    tr/0/o/ for @{$row}{@pure_text};          # substitution on hash slice
    s/(?<!\d)0(?!\d)/o/g for @{$row}{@mixed};
    my @row = @{$row}{@$cols};                # make temp array for printing
    $csv->print(*STDOUT, \@row);
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456

我可能会在“autosplit”模式下使用Perl:

perl -a -p -F"\t" \
     -e '$F[0] =~ s/0/o/g;
         $F[1] =~ s/0/O/g;
         $F[3] =~ s/0/o/g;
         $F[4] =~ s/(\D)0(\D)/\1o\2/g;  # Or other more complex regex
         # ...                          # Other fields can be edited
         $_ = join("\t", @F);           # Reassign fields to $_
        ' data-file
$F[4]
的正则表达式将“20tr0ut”更改为“20trout”;如果需要,可以将其变得更复杂

样本数据的输出:

A       B       C       D       E       F       ...
brown   red     1278076 orange  "20 trout"      123     ...
Green   Orange  90876   Yellow  "18 Salmon"     456     ...

这确实假设是一个严格按制表符分隔的数据文件。如果没有严格按制表符分隔的数据,则包含空格的带引号的字符串会使事情变得复杂;在这一点上,Text::CSV对于读取这些行很有吸引力。

我可能会在“autosplit”模式下使用Perl:

perl -a -p -F"\t" \
     -e '$F[0] =~ s/0/o/g;
         $F[1] =~ s/0/O/g;
         $F[3] =~ s/0/o/g;
         $F[4] =~ s/(\D)0(\D)/\1o\2/g;  # Or other more complex regex
         # ...                          # Other fields can be edited
         $_ = join("\t", @F);           # Reassign fields to $_
        ' data-file
$F[4]
的正则表达式将“20tr0ut”更改为“20trout”;如果需要,可以将其变得更复杂

样本数据的输出:

A       B       C       D       E       F       ...
brown   red     1278076 orange  "20 trout"      123     ...
Green   Orange  90876   Yellow  "18 Salmon"     456     ...

这确实假设了一个严格的制表符分隔的数据文件。如果没有严格的制表符分隔的数据,则包含空格的带引号的字符串会使事情变得复杂;此时,Text::CSV对于读取行很有吸引力。

这里有一种方法,使用数组引用和/或子例程进行简单配置,然后进行替换三:

use strict;
use warnings;

my @subst = ([
  ['this', 'that'],
  ['O', 1],
],[
  ['foo', 'boo'],
  sub {s/a.*//},
]);

sub mk_subst {
  my $list = shift;
  my ($this, $that) = eval { @$list };
  return $list unless defined $this;
  sub { s/\Q$this/$that/ };
}

my @all;
for my $set (@subst) {
  my @list = eval { @$set };
  unless (@list) {
    push @all, [ sub {} ];
    next;
  }
  my @re;
  for my $s (@list) {
    push @re, mk_subst($s);
  }
  push @all, \@re;
}

while (<DATA>) {
  chomp;
  my @list = split /\t/, $_, -1;
  for my $i (0..$#list) {
    for ($list[$i]) {
      for my $funcs ($all[$i]) {
        for my $f (@$funcs) {
          $f->();
        }
      }
    }
  }
  print join("\t", @list), "\n";
}

__DATA__
thisO   fooabca1234
abc 123fooabca1234
使用严格;
使用警告;
我的@subst=([
[‘这个’、‘那个’],
[O',1],
],[
[foo',boo'],
副主席{s/a.*/},
]);
子mk_subst{
我的$list=shift;
我的($this,$that)=eval{@$list};
返回$list,除非定义为$this;
sub{s/\Q$this/$that/};
}
我的所有;
对于我的$set(@subst){
my@list=eval{@$set};
除非(@list){
推@all,[sub{}];
下一个
}
我的@re;
我的$s(@list){
推送@re,mk_subst($s);
}
按@all,\@re;
}
而(){
咀嚼;
my@list=split/\t/,$\u1;
对于我的$i(0..$#列表){
对于($list[$i]){
对于我的$funcs($all[$i]){
对于我的$f(@$funcs){
$f->();
}
}
}
}
打印联接(“\t”,@list),“\n”;
}
__资料__
这是fooabca1234
abc 123食品ABCA1234

这里有一种方法,使用数组引用和/或子例程进行简单配置,然后再进行替换:

use strict;
use warnings;

my @subst = ([
  ['this', 'that'],
  ['O', 1],
],[
  ['foo', 'boo'],
  sub {s/a.*//},
]);

sub mk_subst {
  my $list = shift;
  my ($this, $that) = eval { @$list };
  return $list unless defined $this;
  sub { s/\Q$this/$that/ };
}

my @all;
for my $set (@subst) {
  my @list = eval { @$set };
  unless (@list) {
    push @all, [ sub {} ];
    next;
  }
  my @re;
  for my $s (@list) {
    push @re, mk_subst($s);
  }
  push @all, \@re;
}

while (<DATA>) {
  chomp;
  my @list = split /\t/, $_, -1;
  for my $i (0..$#list) {
    for ($list[$i]) {
      for my $funcs ($all[$i]) {
        for my $f (@$funcs) {
          $f->();
        }
      }
    }
  }
  print join("\t", @list), "\n";
}

__DATA__
thisO   fooabca1234
abc 123fooabca1234
使用严格;
使用警告;
我的@subst=([
[‘这个’、‘那个’],
[O',1],
],[
[foo',boo'],
副主席{s/a.*/},
]);
子mk_subst{
我的$list=shift;
我的($this,$that)=eval{@$list};
返回$list,除非定义为$this;
sub{s/\Q$this/$that/};
}
我的所有;
对于我的$set(@subst){
my@list=eval{@$set};
除非(@list){
推@all,[sub{}];
下一个
}
我的@re;
我的$s(@list){
推送@re,mk_subst($s);
}
按@all,\@re;
}
而(){
咀嚼;
my@list=split/\t/,$\u1;
对于我的$i(0..$#列表){
对于($list[$i]){
对于我的$funcs($all[$i]){
对于我的$f(@$funcs){
$f->();
}
}
}
}
打印联接(“\t”,@list),“\n”;
}
__资料__
这是fooabca1234
abc 123食品ABCA1234
测试如下

> cat temp
br0wn   red   1278076   0range   "20 tr0ut"   123 ...
Green   0range   90876   Yell0w   "18 Salm0n"   456   ...

> perl -F -lane 'for(@F){$_=~s/0/o/g if(/0/ && /[a-zA-Z]+/);} print "@F"' temp
brown red 1278076 orange "20 trout" 123 ...
Green orange 90876 Yellow "18 Salmon" 456 ...
>
测试如下

> cat temp
br0wn   red   1278076   0range   "20 tr0ut"   123 ...
Green   0range   90876   Yell0w   "18 Salm0n"   456   ...

> perl -F -lane 'for(@F){$_=~s/0/o/g if(/0/ && /[a-zA-Z]+/);} print "@F"' temp
brown red 1278076 orange "20 trout" 123 ...
Green orange 90876 Yellow "18 Salmon" 456 ...
>

哇,快速响应,所以我想用awk来做,但我希望能够根据字段名制定不同的规则,比如