从csv文件中提取字母数字文本

时间:2013-03-18 23:59:13

标签: python perl

我有一个位置网格(AI和1-9),在平面文件(* .csv)中以各种形式引用,有时包括空格和随机大小写,例如:9-H,@ b 3,e-4,d4,c6,5h,C2,i9,...是a到i和1到9的任意组合,包括空格,〜@和 - 。

处理提取此类字母数字字符的好方法是什么?理想情况下,输出将在“Notes”之前的另一列或另一个文本文件中。我可以阅读脚本并弄清楚他们做了什么,但是还不够舒服地编写它们。

示例输入文件:

Record  Notes
46651   Adrian reported green-pylons are in central rack. (e-4)
46652   Jose enetered location of triangles in the uppur corner. (b/c6)
46207   [Location: 5h] Gabe located the long pipes in the near the far corner.
46205   Committee-reports are in boxes in holding area, @ b 3).
45164   Caller-nu,mbers @ 1A
45165   All carbon rod tackles 3 F and short (top rack)
45166   USB(3 Port) in C2
45167   Full tackle in b2.
45168    5b; USB(4 port)
45073   SHOVELs+ KIPER ON PET-FOOD (@g6), ALSO ATTEMPT-STALL AND DRAWCORD.
45169   Persistent CORDS ~i9
45170   Deliverate handball moved to D-2 on instructions from Pete
45440   slides and overheads + contact-sheets to 9-H (top bin).
45441   d7-slides and negatives (black and white)
<eof>

所需的输出(字母数字格式,在同一文件或新文件中)

Record  Location    Notes  
46651   E4  
46652   C6  
46205   A1  
...  
46169   I9  

即,始终提取后一组字符。

好的研究员,在“错误后,在模式匹配(m //)中使用未初始化的值$ note后,我只是尝试了并且部分成功了。

#   # starts with anything then space or punctuation then letter then number
if ($note =~ /.*[\s\~\p{Punct}]([a-iA-I])[\s\p{Punct}]*([0-9]).*/) {
    $note =~ s/.*[\s\~\p{Punct}]([a-iA-I])[\s\p{Punct}]*([0-9]).*/$1$2/x;

#   # starts line with letter then number
} elsif ($note =~ /^([a-iA-I])[\s\p{Punct}]*([0-9]).*/) {
   $note =~ s/^([a-iA-I])[\s\p{Punct}]*([0-9]).*/$1$2/x;

#   # after punctuation then number
} elsif ($note =~ /.*[\s\p{Punct}]([0-9])[\s\p{Punct}]*([a-iA-I]).*/) {
   $note =~ s/.*[\s\p{Punct}]([0-9])[\s\p{Punct}]*([a-iA-I]).*/$2$1/x;

#   # beginning of line with number
} elsif ($note =~ /^([0-9])[\s\p{Punct}]*([a-iA-I]).*/) {
    $note =~ s/^([0-9])[\s\p{Punct}]*([a-iA-I]).*/$2$1/x;

#   # empty line or no record of any grid location except "#7 asdfg" format
} elsif  ($note=~ "") {
    $note = "##";

} 

脚本不成功的时间是遇到99994和99993等记录。

99999 norecordofgridhere -
99998个
99997方框#7进入阵列,没有发票。
当我发现场外时,99996在第7小时下降,而coachela在e 8中 4桶后99994箱纸箱 99993 6盒办公文件柜顶层

现在的输出是:

99999 #norecordofgridhere -
99998 ##
99997 E 7方框#7进入阵列,没有发票。
99996 E 8在第7天下降,当我发现场外时,coachela在e 8中 99994 B 4个桶后的4个纸箱 99993 B 6 6箱在办公室文件柜顶层

99994和99993应该有#s。我在哪里失败了?我该怎么解决这个问题?

我认为,有一种更清洁的方式,比如使用Text :: CSV_XS,但是,即使在测试模块已正确安装后,我也遇到草莓perl的故障。所以我回到了activestateperl。

2 个答案:

答案 0 :(得分:0)

...

my $coord;
if ($note =~ /
   (?&DEL)

   ( (?&ROW) (?&SEP)?+ (?&COL)
   | (?&COL) (?&SEP)?+ (?&ROW)
   )

   (?&DEL)

   (?(DEFINE)
      (?<ROW> [a-hA-H]    )
      (?<COL> [1-9]       )
      (?<SEP> [\s~\@\-]++ )
      (?<DEL> ^ | \W | \z )
   )
/x) {
    $coord = $1;
    ( my $row = uc($coord) ) =~ s/[^A-H]//g;
    ( my $col = uc($coord) ) =~ s/[^1-9]//g;
    $coord = "$row$col";
}

...

答案 1 :(得分:0)

使用Text::CSV_XS解析CSV文件,快速准确。

然后构建一个正则表达式来匹配ID。

最后,规范化每个ID。

#!/usr/bin/perl

use v5.10;
use strict;
use warnings;
use autodie;

use Text::CSV_XS;

# Build up the regular expression to look for IDs
my $Separator_Set  = qr{ [- ] }x;
my $ID_Letters_Set = qr{ [a-i] }xi;
my $ID_Numbers_Set = qr{ [1-9] }x;
my $Location_Re = qr{
    \b
    $ID_Letters_Set $Separator_Set? $ID_Numbers_Set |
    $ID_Numbers_Set $Separator_Set? $ID_Letters_Set
    \b
}x;

# Initialize Text::CSV_XS and tell it this is a tab separated CSV
my $csv = Text::CSV_XS->new({
    sep_char => "\t",   # tab separated fields
}) or die "Cannot use CSV: ".Text::CSV_XS->error_diag ();

# Read in and discard the CSV header line.
my $headers = $csv->getline(*DATA);

# Output our own header line    
say "Record\tLocation\tNotes";

# Read each CSV row, extract and normalize the ID, and output a new row.
while( my $row = $csv->getline(*DATA) ) {
    my($record, $notes) = @$row;

    # Extract and normalize the ID
    my($id) = $notes =~ /($Location_Re)/;
    $id = normalize_id($id);

    # Output a new row
    printf "%d\t%s\t%s\n", $record, $id, $notes;
}


sub normalize_id {
    my $id = shift;

    # Return empty string if we were passed in a blank
    return '' if !defined $id or !length $id or $id !~ /\S/;

    my($letter) = $id =~ /($ID_Letters_Set)/;
    my($number) = $id =~ /($ID_Numbers_Set)/;

    return uc($letter).$number;
}

__END__
Record  Notes
46651   Adrian reported green-pylons are in central rack. (e-4)
46652   Jose enetered location of triangles in the uppur corner. (b/c6)
46207   [Location: 5h] Gabe located the long pipes in the near the far corner.
46205   Committee-reports are in boxes in holding area, @ b 3).
45164   Caller-nu,mbers @ 1A
45165   All carbon rod tackles 3 F and short (top rack)
45166   USB(3 Port) in C2
45167   Full tackle in b2.
45168    5b; USB(4 port)
45073   SHOVELs+ KIPER ON PET-FOOD (@g6), ALSO ATTEMPT-STALL AND DRAWCORD.
45169   Persistent CORDS ~i9
45170   Deliverate handball moved to D-2 on instructions from Pete
45440   slides and overheads + contact-sheets to 9-H (top bin).
45441   d7-slides and negatives (black and white)