Вопрос

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

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 или что-то в этом роде вместо взлома строк, который у меня есть?

Это было полезно?

Решение

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

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() потому что я думаю, что моя версия более читабельна, а не потому, что я уверен, что она работает лучше (хотя это могло бы быть).

Другие советы

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

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

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

  • А) Код страны:необязательный префикс ("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      |

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top