Номера телефонов для ссылок в Python - PullRequest
2 голосов
/ 22 декабря 2008

Я работаю над кодом, чтобы превратить телефонные номера в ссылки для мобильного телефона - он у меня есть, но кажется, что он действительно грязный.

import re
from string import digits

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_. ]{0,1}\d{4})')

def numbers2links(s):
    result = ""
    last_match_index = 0
    for match in PHONE_RE.finditer(s):
          raw_number = match.group()
          number = ''.join(d for d in raw_number if d in digits)
          call = '<a href="tel:%s">%s</a>' % (number, raw_number)
          result += s[last_match_index:match.start()] + call
          last_match_index = match.end()
    result += s[last_match_index:]
    return result

>>> numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.")
'Ghost Busters at <a href="tel:5554232368">(555) 423-2368</a>! How about this one: <a href="tel:5554567890">555 456 7890</a>! <a href="tel:5554567893">555-456-7893</a> is where its at.'

Можно ли как-нибудь реструктурировать регулярное выражение или метод регулярных выражений, который я использую, чтобы сделать это чище?

Обновление

Чтобы уточнить, мой вопрос не о правильности моего регулярного выражения - я понимаю, что он ограничен. Вместо этого мне интересно, есть ли у кого-нибудь комментарии о способе подстановки в ссылках телефонных номеров - могу ли я в любом случае использовать re.replace или что-то в этом роде вместо взлома строк, который у меня есть?

Ответы [ 5 ]

5 голосов
/ 22 декабря 2008

Хороший первый дубль :) Я думаю, что эта версия немного более читабельна (и, вероятно, немного быстрее). Ключевым моментом, на который следует обратить внимание, является использование re.sub . Держит нас подальше от неприятных индексов матчей ...

import re

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_.  ]{0,1}\d{4})')
NON_NUMERIC = re.compile('\D')

def numbers2links(s):

   def makelink(mo):
      raw_number = mo.group()
      number = NON_NUMERIC.sub("", raw_number)
      return '<a href="tel:%s">%s</a>' % (number, raw_number)

   return PHONE_RE.sub(makelink, s)


print numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.")

Примечание. В своей практике я не заметил большого ускорения предварительной компиляции простых регулярных выражений, таких как два, которые я использую, даже если вы используете их тысячи раз. Модуль re может иметь какое-то внутреннее кэширование - не удосужился прочитать исходный код и проверить.

Кроме того, я заменил ваш метод проверки каждого символа, чтобы увидеть, находится ли он в string.digits, на другой re.sub(), потому что я думаю, что моя версия более читабельна, а не потому, что я уверен, что она работает лучше (хотя это могло бы быть).

1 голос
/ 22 декабря 2008

Во-первых, общеизвестно, что надежный захват телефонных номеров с помощью единого регулярного выражения затруднен, а сильная тенденция к невозможности невозможна. Не в каждой стране есть определение «телефонного номера», которое является таким же узким, как в США. Даже в США все сложнее, чем кажется (из статьи Википедии о Североамериканском плане нумерации ):

  • A) Код страны: необязательный префикс («1» или «+1» или «001»)
    • ((00|\+)?1)?
  • B) План нумерации Код города (NPA): не может начинаться с 1, цифра 2 не может быть 9
    • [2-9][0-8][0-9]
  • C) Код обмена (NXX): не может начинаться с 1, не может заканчиваться на «11», необязательные скобки
    • \(?[2-9](00|[2-9]{2})\)?
  • D) Код станции: четыре цифры, не все могут быть 0 (я полагаю)
    • (?!0{4})\d{4}
  • E) дополнительное расширение может следовать
    • ([x#-]\d+)?
  • S) части числа разделены пробелами, тире, точками (или нет)
    • [. -]?

Итак, основное регулярное выражение для США будет:

((00|\+)?1[. -]?)?\(?[2-9][0-8][0-9]\)?[. -]?[2-9](00|[2-9]{2})[. -]?(?!0{4})\d{4}([. -]?[x#-]\d+)?
| A       |S   |  |   B                | S   |   C             | S  |  D           | S  |  E      |

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

1 голос
/ 22 декабря 2008

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

В противном случае международным стандартом является ITU E.123 : "Обозначение национальных и международных телефонных номеров адреса электронной почты и веб-адреса "

0 голосов
/ 22 декабря 2008

Почему бы не повторно использовать работу других - например, из RegExpLib.com ?

Мое второе предложение - помнить, что есть и другие страны, кроме США, и у довольно многих из них есть телефоны ;-) Пожалуйста, не забывайте нас при разработке программного обеспечения.

Также существует стандарт для форматирования телефонных номеров; МСЭ E.123 . Мое воспоминание о стандарте состояло в том, что то, что он описывает, не совпадает с популярным использованием.

Редактировать: Я перепутал G.123 и E.123. К сожалению. Реквизит Борцмейер

0 голосов
/ 22 декабря 2008

Несколько вещей, которые очистят существующее регулярное выражение без реального изменения функциональности:

Заменить {0,1} на?, [(] На (, [)] на). Вы также можете просто сделать [2-9] b e a \ d, так что вы можете сделать эти шаблоны \ d {3} и \ d {4} для последней части. Я сомневаюсь, что это действительно увеличит частоту ложных срабатываний.

...