2014-01-16 2 views
3

Я пытаюсь создать регулярное выражение для grep, которое соответствует только действительным доменам.grep valid domain regex

Моя версия работает очень хорошо, но соответствовать следующему недопустимый домен:

@subdom..dom.ext 

Вот мое регулярное выражение:

echo "@dom.ext" | grep "^@[[:alnum:]]\+[[:alnum:]\-\.]\+[[:alnum:]]\+\.[[:alpha:]]\+\$" 

Я работаю с Баш, так что я бежал специальные символы.

образец, который должен соответствовать:

@subdom.dom.ext 
@subsubdom.subdom.dom.ext 
@subsub-dom.sub-dom.ext 

Спасибо за помощь

+0

В случае, если есть необходимость точно Grep и матч только существующий домен высшего уровня, посмотреть на https://stackoverflow.com/questions/14460680/how-to-get-a- list-of-tlds-using-bash-for-building-a-regex –

ответ

6

Действительно полное решение требует больше работы, но вот выстрел (обратите внимание, что префикс @ предполагается):

^@(([a-zA-Z](-?[a-zA-Z0-9])*)\.)*[a-zA-Z](-?[a-zA-Z0-9])+\.[a-zA-Z]{2,}$ 

Вы можете использовать это с egrep (или grep -E), но и с [[ ... =~ ... ]], Баш-х годов regex-matching operator.

делает следующие допущения, которые являются более снисходительными, чем фактические ограничения имен DNS:

  • Только ASCII (не иностранные) буквы допускаются - смотрите ниже Имя интернационализированного домена (IDN) соображения; также, ASCII-формы IDN, например xn--bcher-kva.ch для bücher.ch, не совпадают (хотя было бы легко исправить это).
  • Нет ограничений на количество вложенных поддоменов.
  • Нет ограничений на длину любой метки (компонента названия) и лимита на общую длину имени (для фактических пределов см. here).
  • TLD (последний компонент) состоит только из букв и имеет длину не менее 2.
  • Как субдомен, так и доменные имена должны начинаться с буквы; имя домена должно иметь длину не менее 2; субдоменам разрешено быть однобуквенными.

Вот быстрый тест:

for d in @subdom..dom.ext @dom.ext @subdom.dom.ext @subsubdom.subdom.dom.ext @subsub-dom.sub-dom.ext; do 
[[ $d =~ \ 
    ^@(([a-zA-Z](-?[a-zA-Z0-9])*)\.)*[a-zA-Z](-?[a-zA-Z0-9])+\.[a-zA-Z]{2,}$ \ 
]] && echo YES || echo NO 
done 

Поддержка Internationalized Domain Names (IDN):

Простое улучшение также соответствовать ИДИ, чтобы заменить [a-zA-Z] с [[:alpha:]] и [a-zA-Z0-9] с [[:alnum:]] в над регулярным выражением; то есть:

^@(([[:alpha:]](-?[[:alnum:]])*)\.)*[[:alpha:]](-?[[:alnum:]])+\.[[:alpha:]]{2,}$ 

Предостережение:

  • Не все Unix-подобные платформы полностью поддерживают все буквы Unicode при сопоставлении с [[:alpha:]] или [[:alnum:]]. Например, с использованием локалей на основе UTF-8 OS X 10.9.1, по-видимому, соответствует только латинским диакритическим признакам (например, ü, á) и кириллическим символам (в дополнение к ASCII), тогда как Linux 3.2 похвально представляется охватом всех сценариев, в том числе азиатских и арабские.

  • Непонятно, правильно ли совпадают имена в скриптах написания справа налево.

  • Для полноты картины: даже при том, что регулярное выражение выше не делает никаких попыток применения ограничений длины, пытаясь сделать это с ИДИ будет гораздо более сложным, так как ограничения длины применимы к ASCII кодирования имени (через Punycode), а не оригинал.

Совет шляпы @Alfe для указания проблемы с IDN.

+0

Хорошее объяснение, однако, это не меньше?^@ (([a-zA-Z] (-? [a-zA-Z0-9]) *) \.) + [a-zA-Z] {2} $ – Arka

+0

@Arka: Нет, потому что разрешат однобуквенные доменные имена (например, «@ a.com»), которые недопустимы. Обратите внимание, что первый '(-? [A-zA-Z0-9])' в моем регулярном выражении для _sub_-домена - определяется количественно с помощью '*', тогда как второй - для _domain_ - определяется количественно с '+' , – mklement0

+0

Вы правы, еще раз спасибо. – Arka

0
echo "@dom.ext" | grep -E "^@[a-zA-Z0-9]+([-.]?[a-zA-Z0-9]+)*.[a-zA-Z]+$" 

это сделало работу.

+1

Домены могут начинаться с цифр? – Alfe

+0

Кроме того, вам нужно избежать последнего появления '.'. – mklement0

1

Использование

grep '@[[:alpha:]][[:alnum:]\-]*\.[[:alpha:]][[:alnum:]\-]*\.[[:alpha:]][[:alnum:]\-]*$' 
+0

Вы принимаете 3 компонента (субдомены), но OP также хочет соответствовать доменам (2 компонента). Кроме того, не являются TLD, состоящие только из букв (.com, .info, ...)? – mklement0

+0

Да, правильно. Но когда мы вдавались в такие подробности, мы также могли рассматривать домены юникода (например, www.müller.de), тогда [az] тоже было бы недостаточно, и я боюсь, что '[[: alnum:]]' 'grep' возможно, также неправильно обрабатывать эти умлауты (в зависимости от кодеков и т. д.). Поэтому я думаю, что мы можем оставить это так, как это принято с вашим принятым ответом; если это работает для ОП, этого должно быть достаточно. Если, однако, он хочет получить окончательный ответ, я думаю, что ни одного из наших не хватит ;-) – Alfe

+1

Хорошие моменты, спасибо. Я обновил свой пост и предоставил хотя бы некоторые ответы, а также уточнил ограничения моего решения. – mklement0