Как я могу разобрать номер телефона в Perl?

Я пытаюсь захватить любые цифры перед известным номером линии телефона, если они существуют (в Perl). Не будет тире, только цифры.

Например, скажем, я знаю, что номер строки всегда будет 8675309. 8675309 может иметь или не иметь начальные цифры, если это так, я хочу их захватить. На самом деле нет ограничения на количество первых цифр.

$input          $digits       $number
'8675309'       ''            '8675309'
'8008675309'    '800'         '8675309'
'18888675309'   '1888'        '8675309'
'18675309'       '1'           '8675309'
'86753091'      not a match

/8675309$/ это будет соответствовать тому, как захватить предварительные цифры в одном регулярном выражении?


person user210757    schedule 14.01.2010    source источник
comment
Зачем использовать регулярное выражение? Как насчет index() и substr() или split()? Помните codinghorror.com/blog/archives/001016.html   -  person Kai Huppmann    schedule 14.01.2010
comment
у вас есть пример? в Perl я боюсь, что это будет гораздо более беспорядочный набор вложенных ifs из-за строки переменной длины, но я могу ошибаться   -  person user210757    schedule 14.01.2010
comment
См. ответ Хоббса на stackoverflow.com/questions/2055988/, заданный в течение последних нескольких дней.   -  person brian d foy    schedule 14.01.2010


Ответы (6)


Некоторые регулярные выражения работают лучше в обратном направлении, чем в прямом. Поэтому иногда полезно использовать сексегер, а не регулярные выражения.

my $pn = '18008675309';

reverse($pn) =~ /^9035768(\d*)/;
my $got = reverse $1;

Регулярное выражение чище и позволяет избежать большого количества обратного отслеживания за счет некоторой ерунды с реверсированием ввода и захваченных значений.

В этом случае выигрыш от обратного отслеживания меньше, чем если бы у вас было обычное регулярное выражение для извлечения номера телефона:

Regex:   /^(\d*)\d{7}$/
Sexeger: /^\d{7}(\d*)/

Существует целый класс задач, где этот метод полезен. Для получения дополнительной информации см. сообщение о сексегерах на Perlmonks.

person daotoad    schedule 14.01.2010
comment
@Ragepotato, жаль, что я не изобрел этот термин. Но это незабываемо. - person daotoad; 14.01.2010

my($digits,$number);
if ($input =~ /^(\d*)(8675309)$/) {
  ($digits,$number) = ($1,$2);
}

Квантификатор * является жадным, но это означает, что он соответствует как можно большему количеству при этом допуская совпадение. Итак, изначально, да, \d* пытается сожрать все цифры в $number, но неохотно отказывается от того, что соответствует, посимвольно, пока весь шаблон не совпадет успешно.

Другой подход — отрубить хвост:

(my $digits = $input) =~ s/8675309$//;

Вы можете сделать то же самое без использования регулярного выражения:

my $digits = $input;
substr($digits, -7) = "";

Вышеупомянутое, по крайней мере, с perl-5.10-1, можно было бы даже сжать до

substr(my $digits = $input, -7) = "";
person Greg Bacon    schedule 14.01.2010
comment
мое замешательство в том, что я думал, что (\d*) жадно захватил бы всю строку, но, похоже, это не так. Я думал, вам нужно было сделать регулярные выражения нежадными с опцией? - person user210757; 14.01.2010
comment
@unk, механизм регулярных выражений отступит и попытается удовлетворить условию \d*, насколько это возможно. Он начинает с того, что берет столько, сколько может, а затем отступает по мере необходимости, чтобы попытаться удовлетворить каждое последующее требование. Взгляните на вывод из perl -Mre=debug -e '$foo="18008675309"; $foo =~ /(\d*)8675309/;' - person daotoad; 14.01.2010

Специальные переменные регулярных выражений $` и $& — еще один способ получить эти фрагменты информации. Они содержат содержимое данных, предшествующих совпадению, и само совпадение соответственно.

   if ( /8675309$/ )
      {
      printf( "%s,%s,%s\n", $_, $`, $& );
      }
   else
      {
      printf( "%s,Not a match\n", $_ );
      }
person Mark Wilkins    schedule 14.01.2010

Существует пакет Perl, который работает как минимум с телефонными номерами в Великобритании и США.

Он называется Number::Phone, а код находится где-то на сайте cpan.org.

person Nigel Smith    schedule 28.10.2011

Как насчет /(\d)?(8675309)/? ОБНОВИТЬ:

упс, это должно было быть /(\d*)(8675309)/

person FrustratedWithFormsDesigner    schedule 14.01.2010
comment
Без привязок ^ и $ этот шаблон может совпасть где угодно в целевой строке. - person Greg Bacon; 14.01.2010

может я не понимаю проблемы. Почему есть разница между первым и четвертым примерами:

'8675309'    ''   '8675309'  
...  
'8675309'    '1'  '8675309'

Если все, что вы хотите, это отделить последние семь цифр от всего остального, вы могли бы сказать это так, а не приводить запутанные примеры. Регулярное выражение для этого будет:

/(\d*)(\d{7,7})$/

Если вы не просто предоставили гипотетический номер, а действительно ищете только строки с «8675309» (кажется странным), замените «\d{7,7}» на «8675309».

person gary    schedule 14.01.2010