Могу ли я оптимизировать это регулярное выражение для телефона?

Хорошо, у меня есть это регулярное выражение:

( |^|>)(((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{2})(-)?( )?)?)([0-9]{7}))|((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{3})(-)?( )?)?)([0-9]{6}))|((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{1})(-)?( )?)?)([0-9]{8})))( |$|<)

Он форматирует голландские и бельгийские телефонные номера (мне нужны только те, которые, следовательно, 31 и 32 в качестве кода страны).

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

Принимаются все следующие номера телефонов в европейском формате

0031201234567
0031223234567
0031612345678
+31(0)20-1234567
+31(0)223-234567
+31(0)6-12345678
020-1234567
0223-234567
06-12345678
0201234567
0223234567
0612345678

и следующие ложно отформатированные не

06-1234567 (mobile phone number in the Netherlands should have 8 numbers after 06 )
0223-1234567 (area code with home phone)

в отличие от этого, что хорошо.

020-1234567 (area code with 3 numbers has 7 numbers for the phone as opposed to a 4 number area code which can only have 6 numbers for phone number)

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

Теперь мой вопрос ... видите ли вы способ упростить это регулярное выражение (или даже улучшить его, если вы видите в нем ошибку), сохраняя при этом те же правила?

Вы можете протестировать это на regextester.com

('(| ^ |>)' Предназначен для проверки того, стоит ли он в начале слова, с возможностью того, что ему предшествует новая строка или '>'. Я ищу телефонные номера на страницах HTML.)

Мой первый вопрос: действительно ли вам нужны ВСЕ эти снимки? Разве вы не можете просто взять важные части и переформатировать. Какие уместные части?

Axeman 07.11.2008 01:20

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

youri 07.11.2008 03:25
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
9
2
3 838
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Господи Всевышний, какой бардак! :) Если у вас есть семантические или бизнес-правила высокого уровня (например, те, которые вы описываете, говоря о европейских числах, числах в Нидерландах и т. д.), Вам, вероятно, будет лучше разбить этот единственный тест регулярного выражения на несколько отдельных тестов регулярного выражения, по одному для каждого из ваших правил высокого уровня.

if number =~ /...../  # Dutch mobiles
  # ...
elsif number =~ /..../  # Belgian landlines
  # ...
# etc.
end

Так будет немного легче читать, поддерживать и изменять.

И упорядочите свои тесты по наиболее вероятному совпадению (при условии, что вы достаточно хорошо знаете демографические данные).

tvanfosson 06.11.2008 17:15

Разделите его на несколько выражений. Например (псевдокод) ...

phone_no_patterns = [
    /[0-9]{13}/, # 0031201234567
    /+(31|32)\(0\)\d{2}-\d{7}/ # +31(0)20-1234567
    # ..etc..
]
def check_number(num):
    for pattern in phone_no_patterns:
        if num matches pattern:
            return match.groups

Затем вы просто перебираете каждый шаблон, проверяя, соответствует ли каждый из них ..

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

Это не оптимизация, но вы используете

(-)?( )?

три раза в вашем регулярном выражении. Это заставит вас сопоставить такие номера телефонов

+31(0)6-12345678
+31(0)6 12345678

но также будет соответствовать числам, содержащим тире, за которым следует пробел, например

+31(0)6- 12345678

Вы можете заменить

(-)?( )?

с

(-| )?

чтобы соответствовать либо тире или же, либо пробелу.

Так лучше. Ваше решение спасает персонажа. Я экономил на печатании. :)

Bill the Lizard 06.11.2008 18:54

(31 | 32) выглядит плохо. При сопоставлении 32 механизм регулярных выражений сначала попытается сопоставить 31 (2 символа), потерпит неудачу и вернет два символа назад, чтобы сопоставить 31. Более эффективно сначала сопоставить 3 (один символ), попробовать 1 (сбой), выполнить возврат одного символа и матч 2.

Конечно, ваше регулярное выражение не работает с номерами 0800-; это не 10 цифр.

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

youri 06.11.2008 19:13
Ответ принят как подходящий

Первое наблюдение: чтение регулярного выражения - кошмар. Он требует режима Perl / x.

Второе наблюдение: в выражении много, и много, и много захватывающих скобок (42, если я правильно посчитал; а 42, конечно же, «Ответ на жизнь, Вселенную и все» - см. Дуглас Адамс ») Автостопом по Галактике », если вам нужно это объяснять).

Ящерица Билл отмечает, что вы несколько раз использовали «(-)?( )?». У этого нет очевидного преимущества по сравнению с '-? ?' или, возможно, '[- ]?', если только вы действительно не намерены фиксировать фактическую пунктуацию отдельно (но существует так много захватывающих скобок, которые определяют, какие элементы '$ п' использовать было бы сложно) .

Итак, попробуем отредактировать копию вашего однострочного письма:

( |^|>)
(
    ((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{2})(-)?( )?)?)([0-9]{7})) |
    ((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{3})(-)?( )?)?)([0-9]{6})) |
    ((((((\+|00)(31|32)( )?(\(0\))?)|0)([0-9]{1})(-)?( )?)?)([0-9]{8}))
)
( |$|<)

Хорошо - теперь мы можем видеть регулярную структуру вашего регулярного выражения.

Отсюда возможен гораздо больший анализ. Да, регулярное выражение может быть значительно улучшено. Первый, очевидный, состоит в том, чтобы извлечь часть международного префикса и применить ее один раз (необязательно или потребовать ведущий ноль), а затем применить национальные правила.

( |^|>)
(
    (((\+|00)(31|32)( )?(\(0\))?)|0)
    (((([0-9]{2})(-)?( )?)?)([0-9]{7})) |
    (((([0-9]{3})(-)?( )?)?)([0-9]{6})) |
    (((([0-9]{1})(-)?( )?)?)([0-9]{8}))
)
( |$|<)

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

( |^|>)
(
    (((\+|00)3[12] ?(\(0\))?)|0)
    (((([0-9]{2})-? ?)?)[0-9]{7}) |
    (((([0-9]{3})-? ?)?)[0-9]{6}) |
    (((([0-9]{1})-? ?)?)[0-9]{8})
)
( |$|<)

Мы можем заметить, что регулярное выражение не применяет правила для кодов мобильных телефонов (поэтому оно не требует, например, чтобы за «06» следовало 8 цифр). Также кажется, что 1, 2 или 3-значный «обменный» код может быть необязательным, даже с международным префиксом - вероятно, не то, что вы имели в виду, и исправление этого удаляет еще несколько круглых скобок. После этого мы можем убрать еще несколько скобок, что приведет к следующему:

( |^|>)
(
    (((\+|00)3[12] ?(\(0\))?)|0)    # International prefix or leading zero
    ([0-9]{2}-? ?[0-9]{7}) |        # xx-xxxxxxx
    ([0-9]{3}-? ?[0-9]{6}) |        # xxx-xxxxxx
    ([0-9]{1}-? ?[0-9]{8})          # x-xxxxxxxx
)
( |$|<)

И я надеюсь, что отсюда вы сможете поработать над дальнейшей оптимизацией.

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

youri 06.11.2008 19:15

очень старая шишка, но я только что видел часть про 42 ... это хорошо: P Ура, приятель: P

youri 27.04.2011 22:22

как вы можете заставить это работать с PHP и preg_replace?

Sanne 17.12.2013 19:29

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