PERL: Регулярное выражение для чтения Social Security # с тире

Я пишу perl-скрипт, который считывает номера социального страхования из файла, ищет информацию в нескольких таблицах и выводит в файл с разделителями. Я пишу на PERL 5 и имею дело с IBM informix. У меня такое ощущение, что проблема в моем REGEX. Я получаю несколько строк следующей ошибки:

Ошибка выполнения DBD::Informix::st: SQL: -1213: Ошибка процесса преобразования символа в числовое в ./corylist.pl, строка 61, строка 461. Ошибка DBD::Informix::st fetchrow_array: SQL: -400: Fetch попытка на неоткрытом курсоре. на ./corylist.pl строка 63, строка 461.

Может ли кто-нибудь подтолкнуть меня в правильном направлении? Спасибо!

while(<IN>) {
    $id = $_;
    chomp $id;
    $id =~ m/^\d{3}-\d{2}-\d{4}$/;
    #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;
}

person Jim    schedule 13.02.2017    source источник
comment
Ваше регулярное выражение только соответствует чему-то, но вы никогда не действуете на него. Вы не подменяете, вы не захватываете. Эта линия по сути бесполезна. У вас также нет кавычек в вашем SQL, где вы используете $id. Вместо этого вы должны использовать заполнитель. И из сообщения об ошибке я бы сказал, что это числовое поле, поэтому вам нужно избавиться от тире.   -  person simbabque    schedule 13.02.2017
comment
Вы понимаете, что $x .= $fname." | ".$lname." | ".$addr1." | ".$addr2." | ".$city." | ".$st." | ".$zip." | ".$ctry." | ".$cnty." | " можно записать как $x .= "$fname|$lname|$addr1|$addr2|$city|$st|$zip|$ctry|$cnty|"?   -  person Borodin    schedule 13.02.2017
comment
Бесполезно prepare выполнять один и тот же оператор каждый раз в цикле while. $sth = $db1->prepare($STMT) следует вынести за пределы блока.   -  person Borodin    schedule 13.02.2017
comment
@Borodin Я даже не видел, что prepare был в петле. Я подумывал предложить join '|', ..., но ладно. Text::CSV это.   -  person simbabque    schedule 13.02.2017
comment
@simbabque: я не удивлен. Эта последняя закрывающая фигурная скобка на самом деле находится на один уровень ниже. Брекеты не совпадают.   -  person Borodin    schedule 13.02.2017
comment
@simbabque: А. Я также не заметил $id, спрятанного во всем этом SQL!   -  person Borodin    schedule 13.02.2017
comment
Какое дело вам до чтения номеров социального страхования? Вы работаете на правительство, и это часть вашей работы?   -  person    schedule 13.02.2017


Ответы (1)


Ваше регулярное выражение в порядке, но оно ничего не делает.

$id =~ m/^\d{3}-\d{2}-\d{4}$/;

Эта строка будет истинной, если $id соответствует шаблону. Больше ничего не делает.

Не удалось преобразовать символ в числовое значение

В сообщении об ошибке говорится, что ваша база данных запрашивает число, но получает что-то, что не может преобразовать в то, что получила. Поскольку вы используете $id в запросе, это должно быть тире. Так что можно предположить, что ваш SSN является каким-то целым числом.

Самый простой способ избавиться от сообщения об ошибке — просто удалить все, что не является числом. Это избавит от тире - и всего, что люди хотели ввести.

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

    # ...
}

Теперь можно заняться вставкой. Но вам действительно не следует вставлять данные, записывая переменную непосредственно в ваш SQL без надлежащего цитирования. Это приглашение к внедрению SQL. Вместо этого используйте заполнители.

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

Теперь, когда вы execute выполняете оператор prepared, вы передаете $id.

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

Если вы имеете дело с большим файлом, было бы неплохо использовать fetchrow_arrayref или fetchrow_hashref вместо fetchrow_array, потому что копирование всех переменных довольно затратно. Также просмотрите эту презентацию, чтобы узнать больше об использовании DBI в быстрый способ.

Вы можете заглянуть в SSN::Validate для фактической проверки номеров социального страхования. Если вы используете это, кажется, что вам не нужно выполнять очистку, предложенную выше.

Вы также можете посмотреть на Text::CSV, чтобы получить более чистый способ создания выходных данных в формате CSV.

person simbabque    schedule 13.02.2017