【问题标题】:Count pattern occurrence in each line of file?计算每行文件中出现的模式?
【发布时间】:2014-04-22 15:54:12
【问题描述】:

我的文件如下所示:

id12 ack dko hhhh chfl dkl dll chfl
id14 slo ksol chfl dloo
id13 mse
id23 clos chfl dll alo

grep -c 'chfl' filename,给了我chfl 的出现次数,但我想计算每行chfl 的出现次数。像这样:

id12 2
id14 1
id13 0
id23 1

另外,我如何对两个模式进行相同的匹配?喜欢chfldll

【问题讨论】:

  • 如果你有一个字符串achflop,这也将部分匹配。这就是你想要的吗?
  • 另外,如果您有两种(或更多)搜索模式,您想要一个总计数,还是每个单词一个?

标签: regex perl sed awk grep


【解决方案1】:

处理多个字符串的 Perl 版本。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

die "Usage: $0 pattern [pattern ...] file\n" unless @ARGV > 1;

my @patterns;
until (@ARGV == 1) {
  push @patterns, shift;
}

my $re = '(' . join('|', map { "\Q$_\E" } @patterns) . ')';

my %match;
while (<>) {
  if (my @matches = /$re/g) {
    $match{$_}++ for @matches;
  }
}

say "$_: $match{$_}" for sort keys %match;

几个测试运行:

$ ./cgrep chfl dll cgrep.txt 
chfl: 4
$ ./cgrep chfl dll cgrep.txt 
chfl: 4
dll: 2

【讨论】:

    【解决方案2】:
    perl -lane 'undef $c;
                for(@F){$c++ if(/^chfl$/)};
                print "$F[0] ",$c?$c:"0"' your_file
    

    或者简单地说:

    perl -lane '$c=0;
                for(@F){$c++ if(/^chfl$/)};
                print "$F[0] $c"' your_file
    

    测试如下:

    > cat temp
    id12 ack dko hhhh chfl dkl dll chfl
    id14 slo ksol chfl dloo
    id13 mse
    id23 clos chfl dll alo
    > perl -lane '$c=0;for(@F){$c++ if(/^chfl$/)};print "$F[0] $c"' temp
    id12 2
    id14 1
    id13 0
    id23 1
    > 
    

    同样在awk中:(这里的逻辑与perl中的逻辑相同)

    awk '{a=0;
         for(i=1;i<=NF;i++)if($i~/chfl/)a++;
         print $1,a}' your_file
    

    【讨论】:

    • -a 表示将行拆分为一个数组@F,每个单词作为一个数组元素。现在计算当前数组中与 chfl 匹配的所有单词。用 0 初始化每一行的计数器。然后打印数组中的第一个元素和计数器值。
    • 那么其他值有什么作用呢? l ,n, e@F 不需要像 $c 这样的声明吗?
    • No @F 不需要声明。它是一个隐式创建的数组。
    【解决方案3】:

    用 grep bash 一个班轮:

    while read line ; do echo $line | grep -o 'chfl' | wc -l  ; done < your_file
    

    -o 在新行中输出每一个出现的次数,然后 wc 对其进行计数。

    编辑多个模式:

    patterns=(chfl dll)
    
    while read line ; do
        for pattern in ${patterns[@]} ; do
            echo -ne $pattern"\t" ; echo $line | grep -o $pattern | wc -l 
        done
    done < your_file
    

    【讨论】:

      【解决方案4】:
      perl -ne 'my $c=s/chfl//g||0;my $d=s/dll//g||0;s/ .*//s;print "$_ chfl $c dll $d\n"' file
      

      解释:

      • s///g 在标量上下文中返回替换的次数
      • ||0 如果没有匹配项,请确保将变量设置为零
      • s/ .*//s$_ 的第一个空格中丢弃所有内容,只留下 id

      它将产生以下输出:

      id12 chfl 2 dll 1
      id14 chfl 1 dll 0
      id13 chfl 0 dll 0    
      id23 chfl 1 dll 1
      

      【讨论】:

        【解决方案5】:

        你可以用这个awk

        awk '{d=c=0;for(i=1;i<=NF;i++){ if($i ~ /chfl/)c++; if($i ~ /dll/)d++;} print $1,c,d}' yourfile
        

        【讨论】:

          【解决方案6】:

          awk的另一个版本:

          $ awk '{c1=gsub(var1,x);c2=gsub(var2,x);print $1,var1"="c1,var2"="c2}' var1="chfl" var2="dll"  file
          id12 chfl=2 dll=1
          id14 chfl=1 dll=0
          id13 chfl=0 dll=0
          id23 chfl=1 dll=1
          

          只需在文件末尾传递要计算的变量即可。

          【讨论】:

            【解决方案7】:

            使用这个:

            awk 'BEGIN {print "id\tchfl\tdll\n--------------------"}{c=d=i=0;while(i++<NF){if($i=="chfl")c++; if($i=="dll")d++}; print $1,c,d}' OFS="\t" file
            id      chfl    dll
            --------------------
            id12    2       1
            id14    1       0
            id13    0       0
            id23    1       1
            

            【讨论】:

            • 我的模式实际上就像 clfl|4blabla 和 dll|xyzabc。此解决方案无法显示确切的计数
            • @user3428782 然后更新您的帖子以显示您需要解决的数据。此解决方案适用于上述数据。
            【解决方案8】:

            怎么样:

            my %res;
            while(<DATA>) {
                chomp;
                my ($id,$rest) = $_ =~ /^(\S+)(.*)$/;
                $res{chfl}{$id} =()= $rest =~ /(chfl)/g;
                $res{dll}{$id} =()= $rest =~ /(dll)/g;
            }
            say Dumper\%res;
            
            __DATA__
            id12 ack dko hhhh chfl dkl dll chfl
            id14 slo ksol chfl dloo
            id13 mse
            id23 clos chfl dll alo
            

            输出:

            $VAR1 = {
                      'dll' => {
                                 'id13' => 0,
                                 'id12' => 1,
                                 'id23' => 1,
                                 'id14' => 0
                               },
                      'chfl' => {
                                  'id13' => 0,
                                  'id12' => 2,
                                  'id23' => 1,
                                  'id14' => 1
                                }
                    };
            

            【讨论】:

            • 不过,使用散列会破坏行的顺序。如果 id 不是唯一的,它将不起作用。
            猜你喜欢
            • 2011-02-23
            • 2014-03-12
            • 2021-12-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-06-01
            相关资源
            最近更新 更多