在许多文本文件中搜索多个字符串,计算组合的匹配数

时间:2015-03-04 21:04:23

标签: regex bash perl shell data-structures

我努力实现报道练习的自动化,并希望得到一些指示或建议。

我有几十万个小(<5kb)文本文件。每个都包含一些变量,我需要计算匹配每个变量组合的文件数。

每个文件都包含设备编号,例如/ 001 / /002 /.../006/。

每个文件还包含一个日期字符串,例如01.10.14(dd.mm.yy)

某些文件包含&#39;状态&#39;字符串总是&#34;未结算&#34;

我需要一种方法来浏览Linux系统上的每个文件(分布在几个子目录中),并生成一个按设备计算的报告文件&#39;每个日期戳(6个月范围)包含多少个文件,每个日期包含状态字符串。

报告可能如下所示: 设备,日期,文件总数 设备,日期,总数&#34;未结算&#34;计数

e.g。

/001/, 01.12.14, 356
/001/, 01.12.14, 12
/001/, 02.12.14, 209
/001/, 02.12.14, 8 
/002/, 01.12.14, 209
/002/, 01.12.14, 7

等等

换句话说:

Foreach /device/
Foreach <date>
count total matching files - write number to file
count toal matching 'not settled' files - write number to file

要匹配的每个字符串都可以出现在文件中的任何位置。

我尝试使用grep管道输入第二个(和第三个)grep命令,但是我想自动执行此操作并循环遍历变量(6个设备,大约180个日期,2个状态字符串)。我怀疑Perl和Bash是答案,但我不在我的深处。

任何人都可以推荐一种方法吗?

编辑:评论中提到的一些示例数据。该信息基本上是来自收据的收据数据 - 如将被发送到打印机。这是一个示例(识别出去除的位)。

c0!                       SUBTOTAL     11.37   
c0!   ! T O T A L      11.37! 
c0!   19 ITEMS                                 
c0!   C a s h             ?            11.37   
vu p022c0!                                            
c0!   NET TOTAL           VAT  A       10.87   
c0!   VAT                 00.0%         0.00   
c0!   NET TOTAL           VAT  B        0.42   
c0!   VAT                 20.0%         0.08   
c0!  *4300 772/080/003/132 08.01.15 11:18 A-00 

      Contents = Not Settled

在上面的例子中,我正在寻找/ 003 /,08.01.15和&#34;未定居&#34;

非常感谢。

2 个答案:

答案 0 :(得分:1)

首先,将所有内容读入SQLite数据库,然后针对您的内容运行查询。如果您需要调整任何内容,将数据放入SQL数据库将节省您的时间。此外,如果您设置了正确的表,即使是简单的SQL也可以解决这类问题。

答案 1 :(得分:1)

首先,我同意@Sinan :-)

以下内容可能会起到黑客攻击文件数据的作用。

# report.pl
use strict;
use warnings;    
use Data::Dumper;

my %report;
my ($date, $device) ;

while (<>) {

 next unless m/^ .* 
    (?<device>\/00[1-3]\/) .* 
    (?<date>\d{2}\.\d{2}\.\d{2}) 
    .*$/x ; 

  ($date, $device,) = ($+{date}, $+{device});

  $_ = <> unless eof;

  if (/Contents/) { 
     $report{$date}{$device}{"u_count"}++ ;
  } 
  else {
     $report{$date}{$device}{"count"}++ ; 
  }
}

print Dumper(\%report)

这似乎与下面显示的格式的数据文件集合一起使用(因为您没有说明或显示Contents = Not Settled出现的位置,我认为它是 的一部分最后一行以及每个文件的单独最后一行中的设备ID 。)

<强>解释

  • 该脚本读取在while(<>){}循环中作为glob传递的所有文件的STDIN。首先,next unless m/ ...跳过前面的输入行,直到它与具有设备和日期信息的行匹配。

  • 接下来,匹配使用named capture groups?<device> ?<date>来保存找到的模式的值,并将这些值放在相应的变量(($date, $device,) = ($+{date}, $+{device});)中。这些可能只是是$1$2但是命名让我在这里组织起来。

  • 然后,如果有另一行要阅读$_ = <> unless eof;,请阅读并尝试最后一组条件匹配,以便添加到$counts$u_counts

数据文件格式:

file1.data

c0! SUBTOTAL 11.37
c0! ! T O T A L 11.37! c0! 19 ITEMS
c0! C a s h ? 11.37
vu p022c0!
c0! NET TOTAL VAT A 10.87
c0! VAT 00.0% 0.00
c0! NET TOTAL VAT B 0.42
c0! VAT 20.0% 0.08
c0! *4300 772/080/003/132 08.01.15 11:18 A-00   

file2.data

c0! SUBTOTAL 11.37
c0! ! T O T A L 11.37! c0! 19 ITEMS
c0! C a s h ? 11.37
vu p022c0!
c0! NET TOTAL VAT A 10.87
c0! VAT 00.0% 0.00
c0! NET TOTAL VAT B 0.42
c0! VAT 20.0% 0.08
c0! *4300 772/080/002/132 08.01.15 11:18 A-00 
Contents = Not Settled

(此处列出了一组用于测试的文件:http://pastebin.com/raw.php?i=7ALU80fE)。

perl report.pl file*.data

Data::Dumper 输出

$VAR1 = {
          '08.01.15' => {
                          '/002/' => {
                                       'u_count' => 4
                                     },
                          '/003/' => {
                                       'count' => 1
                                     }
                        },
          '08.12.15' => {
                          '/003/' => {
                                       'count' => 1
                                     }
                        }
        };

通过使用keys()(日期)迭代哈希并检索每台机器的内部哈希值和计数值,您可以生成报告。真的,最好有一些测试来确保一切按预期工作 - 或者只是像@sinan_Ünür建议的那样:使用SQLite!

NB :此代码未经过广泛测试: - )