PERL:用破折号读取社会保障号的正则表达式

Posted

技术标签:

【中文标题】PERL:用破折号读取社会保障号的正则表达式【英文标题】:PERL: Regular Expression for reading Social Security # with Dashes 【发布时间】:2017-02-13 16:56:05 【问题描述】:

我正在编写一个 perl 脚本,它从文件中读取社会安全号码,在多个表中查找信息并输出到分隔文件。我正在使用 PERL 5 编写并处理 IBM informix。我觉得问题出在我的正则表达式上。我收到多行以下错误:

DBD::Informix::st 执行失败:SQL:-1213:字符到数字的转换过程在 ./corylist.pl 第 61 行第 461 行失败。 DBD::Informix::st fetchrow_array 失败:SQL:-400:在未打开的游标上尝试获取。在 ./corylist.pl 第 63 行,第 461 行。

有人可以将我推向正确的方向吗?谢谢!

while(<IN>) 
    $id = $_;
    chomp $id;
    $id =~ m/^\d3-\d2-\d4$/;
    #print "$id\n";

$STMT = <<EOF;
select  i.ss_no,
    i.fullname,             i.firstname,i.lastname,i.addr_line1,i.addr_line2,i.city,i.st,i.zip,r.res_ctry,r.res_cty,
    i.phone,NVL(aa.phone," ") cell,NVL(a.line1," ") stuemail,NVL(pa.line1," ") peremail

  from  id i,
    prof r,
    outer aa_rec a,
    outer aa_rec aa,
    outer aa_rec pa
where   i.ss_no = $id
and     i.id = r.id
and     i.decsd <> "Y"
and a.id = i.id and a.aa = "EML" and a.end_date is null
and pa.id = i.id and pa.aa = "OEML" and pa.end_date is null
and pa.beg_date = (select max(beg_date) from aa_rec where aa = "OEML" and id=$id and end_date is null)
and aa.id = i.id and aa.aa = "CELL" and aa.end_date is null
group by     ss_no,fullname,firstname,lastname,addr_line1,addr_line2,city,st,zip,res_ctry,res_cty,phone,cell,stuemail,peremail
order   by fullname, ss_no
EOF

$sth = $db1->prepare($STMT);
$sth->execute();

while (($id,$fullname,$fname,$lname,$addr1,$addr2,$city,$st,$zip,$ctry,$cnty,$phone,$cell,$stuemail,$peremail) = $sth->fetchrow_array()) 

    $x = $id." | ". $fullname." | ";
    $x .= $fname." | ".$lname." | ".$addr1." | ".$addr2." | ".$city." | ".$st." | ".$zip." | ".$ctry." | ".$cnty." | ";
    $x .= $phone." | ".$cell." | ".$stuemail." | ".$peremail." | \n";
    print $out_fh $x;

【问题讨论】:

你的正则表达式只匹配某些东西,但你从不对其采取行动。你不替代,你不捕获。那条线基本上没用。您在使用$id 的SQL 中也没有引号。您应该改用占位符。从错误消息中我会说它是一个数字字段,所以你需要去掉破折号。 你知道$x .= $fname." | ".$lname." | ".$addr1." | ".$addr2." | ".$city." | ".$st." | ".$zip." | ".$ctry." | ".$cnty." | "可以写成$x .= "$fname|$lname|$addr1|$addr2|$city|$st|$zip|$ctry|$cnty|"吗? while 循环中每次都使用相同的语句prepare 是一种浪费。 $sth = $db1-&gt;prepare($STMT) 应该移到块外。 @Borodin 我什至没有看到prepare 在循环中。我考虑过建议join '|', ...,但是很好。 Text::CSV 是。 @simbabque:我并不感到惊讶。最后一个右括号实际上是向下一层。大括号不匹配。 【参考方案1】:

你的正则表达式很好,但它什么也没做。

$id =~ m/^\d3-\d2-\d4$/;

如果$id 与模式匹配,则该行为真。它什么也不做。

字符到数字的转换过程失败

错误消息说您的数据库需要一个数字,但得到了一些它无法转换它得到的东西。由于您在查询中使用$id,因此必须是破折号。因此,假设您的 SSN 是某种整数是省事的。

消除错误消息的最简单方法是删除任何不是数字的内容。这将消除破折号- 以及人们想输入的任何其他内容。

while ( my $id = <IN>) 
    chomp $id;
    $id =~ s/\D//g; # remove any non-digits

    # ...

现在您可以进行插入了。但是你真的不应该通过在没有正确引用的情况下将变量直接写入 SQL 来插入数据。那是an invitation for SQL injection。请改用placeholders。

my $sql = "SELECT * FROM foo WHERE bar=?";

现在当你executeprepared 语句时,你传递$id

my $sth = $dbh->prepare($sql);
$sth->execute($id);

如果您处理的是 文件,最好使用fetchrow_arrayreffetchrow_hashref 而不是fetchrow_array,因为所有变量的复制都非常昂贵。另请查看this presentation,了解有关快速使用 DBI 的更多信息。

您可能需要查看 SSN::Validate 以实际验证社会安全号码。如果您使用它,您似乎不需要执行上面建议的清理操作。

您还可以查看 Text::CSV 以更简洁地创建 CSV 输出。

【讨论】:

以上是关于PERL:用破折号读取社会保障号的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

谁给我营业执照注册号的正则表达式和税务登记号的正则表达式,万分感谢!

破折号分隔字符串中负值和正值的正则表达式

正则表达式用破折号、空格破折号、点空间、点和带有空字符串的撇号替换空格

IBAN 正则表达式包括空格和破折号

perl 正则表达式 匹配多行的问题

在 Perl 正则表达式中展开环境变量