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->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=?";
现在当你execute
prepare
d 语句时,你传递$id
。
my $sth = $dbh->prepare($sql);
$sth->execute($id);
如果您处理的是大 文件,最好使用fetchrow_arrayref
或fetchrow_hashref
而不是fetchrow_array
,因为所有变量的复制都非常昂贵。另请查看this presentation,了解有关快速使用 DBI 的更多信息。
您可能需要查看 SSN::Validate 以实际验证社会安全号码。如果您使用它,您似乎不需要执行上面建议的清理操作。
您还可以查看 Text::CSV 以更简洁地创建 CSV 输出。
【讨论】:
以上是关于PERL:用破折号读取社会保障号的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章
谁给我营业执照注册号的正则表达式和税务登记号的正则表达式,万分感谢!