Показать сообщение отдельно
Старый 04.11.2011, 23:23   #1
Randomize
[object Object]
 
Аватар для Randomize
 
Регистрация: 01.08.2008
Адрес: В России
Сообщений: 4,355
Написано 2,471 полезных сообщений
(для 6,852 пользователей)
Готовим регулярные выражения: Проверка строки по шаблону

Вечер добрый, мои дорогие пекари.
Сегодня я решил окунуть вас с головой в такую часто вызывающую у многих головную боль тему как "Регулярные выражения".
Кто не в курсе эта такой особый способ работы с текстом. И применений ему масса. И эту массу для наполнения ваших булочек мы сегодня будем разбирать по составу :B

Сегодня мы будем проверять строку по шаблону.

Вам понадобится:
Онлайн тестер регулярных выражений
http://www.functions-online.com/preg_match.html
Как юзать под оффтопом:

subject - наш вводимый текст
pattern - наше выражение
flags и offset пока не трогаем.

В результате выполнения нас пока что интересует только result.
Он булевой:
1 - строка валидна
0 - строка не валидна


Или использовать вот такое на своём веб сервере:
<?
$pattern = (isset($_POST['pattern'])) ? $_POST['pattern'] : '';
$subject = (isset($_POST['subject'])) ? $_POST['subject'] : '';
$pattern = stripslashes($pattern);
$subject = stripslashes($subject);
?>
<hr />
<form action ="" method="post">
    Pattern:
    <input style="width: 370px; padding: 5px;" name="pattern" type="text" value="<?= $pattern?>" /><br />
    Subject:
    <textarea style="width: 370px; padding: 5px;" cols="20" rows="10" name="subject"><?= $subject?></textarea>
    <input type="submit" value="Выполнить" />
</form>

<?= (@preg_match($pattern$subject)) ? 'Да' 'Неа'?>



И так - без вступительных речей.
Начнём по мужски сразу в лоб:
/^http(s?):\/\/[a-z0-9-.]+(:[0-9]+)?(\/(.*))?$/i
Да это же похоже на:
私の馬を見て、私の馬は素晴らしいです!

Первое, что бросается в глаза это http. Угу, значит речь идёт об URL.

Для начала давайте подумаем из чего же состоит URL и каких видов они бывают.
* Нас на данный момент интересуют только http.

Стандартный вид:
http://domain.tld/dir/script.ext

Тоже самое но с добавлением защищённого(http) соединения:
https://domain.tld/dir/script.ext

Так же в URL может быть указан порт вот таким образом:
https://domain.tld:7777/dir/script.ext

Давайте пометим части цветами:

https://domain.tld:7777/dir/script.ext

И легенда.
¦ - префикс "s" для зашифрованного соединения (не обязателен)
¦ - доменное имя
¦ - порт (не обязателен)
¦ - путь после домена (не обязателен)

Ну что, господа, уже представили себе как это реализовывать на всяких такм strpos substr и тд? Сложно, да? А на регулярках это займёт 1 строку.

Давайте продумаем алгоритм.
1) Проверка есть ли в начале http если нет, то стоп.
2) Существует ли приставка "s" к http? Есть - оставляем, нет - фиг с ним едем дальше.
3) Введён ли домен используя сиволы a-z 0-9 точка и дефиз(русские домены пока не берём) есть? идём дальше - иначе стоп.
4) Введён ли порт? Начинается с ":" и далее только цифры 0-9 и их сколько угодно (на самом деле нет, но мы же только начинаем).
5) Есть "/"? Если да то пофигу и если нет тоже :D Но проверить надо дабы понять где кончается домен а где там начинается путь.

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

Сообщение от Регулярочка
/^...$/
/ - управляющий символ. Им обрамляется всё выражение целиком.
^ - старт строки.
$ - конец строки.

Дальше прямым текстом пишем что в начале строки должен быть http:

Сообщение от Регулярочка
/^http$/
Через такое выражение пройдёт только фраза "http".

Общие понятия по под-выражениям и диапазонам/наборам символов:
[...] - диапазон или набор символов.
Например:
[a-z] - 1 символ, который может принимать значения от a до z
[0-9] - 1 символ, который может принимать значения от 0 до 9
[0-9a-z] - 1 символ, который может принимать значения от 0 до 9 или от a до z
[0-9a-zA-Z] - 1 символ, либо любая буква англ. алфавита либо любая 1 цифра
[ab12] - 1 символ, который может принимать значения a,b,1,2 но никакие другие

Диапазон в развёрнутом виде и с 1 вариантом пишется без скобок, хотя никто не запрещает писать в скобках например так:
[a][s][s]

Для указания любого произвольного символа используется точка "."
Это делается так "[.]" или проще так "."
Например:
[.о.о.] под него подпадут слова "солод", "молод"

Так же мы можем указывать для таких диапазонов количество вхождений:
[а] - 1 буква "а"
[а]+ - 1 и более буква "a"
[a]* - сколько угодно "а" и нисколько тоже
[а]{3} - 3 буквы "а"
[а]{3,} - 3 и более букв "а"
[а]{1, 12} - от 1 до 12 букв "а"

Получается, что:
[a]* эквивалентен [a]{0,}
[a]+ эквивалентен [a]{1,}
[a]? эквивалентен [a]{0,1}


() - подвыражение. Нужно для группирования наборов символов внутри основного выражения.
Например:
([a-z][A-Z][0-9]) - говорит о том что тут 3 символа буква в нижнем регистре, буква в верхнем, цифра
Так же такие подвыражения будут возвращены в результат ф-ции ($matches)

Флаги для выражений или диапазонов (ставить после):
+ - выражение может повторяться от 1 до скольки угодно раз
? - это выражение может отсутствовать (т.е. если нет такого вхождения то нет)
{число} - это выражение повторяется указаное число раз. Так же можно указать диапазон например {2-3}
* - это выражение повторяется сколько угодно раз и может не быть вовсе


Теперь добавим первое условие - наличие "s"
(..)-подвыражение
? - флаг внутри выражения, говорящий о том что соблюдение не обязательно

Сообщение от Регулярочка
/^http(s?)$/
Тут уже пройдёт "http" и "https".
Теперь нам надо добавить "://" если c ":" всё в порядке, то с символом / уже нет - он управляющий! Его надо экранировать.
Это делается так: "\/\/" что равнозначно: "//"

Сообщение от Регулярочка
/^http(s?):\/\/$/
Далее домен: Буквы от a-z цифры 0-9, тире и точка и их в общей сложности может быть сколько угодно.
[a-z0-9-.]+

Сообщение от Регулярочка
/^http(s?):\/\/[a-z0-9-.]+$/
Символ плюса на конце диапазона говорит что выражение может повторяться от 1 до скольки угодно раз.
Теперь ссылки вида:
http://boolean.name
https://boolean.name
https://boo.le-an.na-me
Пройдут проверки. Слеш на конце, кстати, обломает проверку ведь его нигде не ждут :B

Теперь порт. В начала уже знакомый нам ":" потом некоторое кол-во цифр:
(:[0-9]+)?
Разберём скобку.
( - начало подвыражения
: - нужный для порта символ двоеточия
[0-9] - этот диапазон символов, в данном случае нас интересуют только цифры
+ - Указывает количество вхождений - сколько угодно раз, но не меньше 1го символа
) - конец подвыражения
? - это подвыражение не обязательно

Сообщение от Регулярочка
/^http(s?):\/\/[a-z0-9-.]+(:[0-9]+)?$/
Отлично! Теперь у нас спокойно пролезают:
https://domain.tld:8080
http://dom-ain.tld
https://domain.gov.ua.tld:113

Теперь завершающий этап - всё что после слеша:

(
\/ - наш заветный слеш
(.*) - всё что угодно (даже ничего) и сколько угодно
)? - всё подвыражение не обязательно

Сообщение от Регулярочка
/^http(s?):\/\/[a-z0-9-.]+(:[0-9]+)?(\/(.*))?$/
Теперь через наше выражение пройдёт уже почти любой url:

http://domain.tld/newthread.php?do=postthread
https://domain.tld/newthread.php?do=postthread
http://domain.tld:80/newthread.php?do=postthread

Осталось пофиксить последний изъян. Наше выражение чувствительно к регистру. Это легко исправить добавив в самый конец глобальный флажок i.
Вот так:
Сообщение от Регулярочка
/^http(s?):\/\/[a-z0-9-.]+(:[0-9]+)?(\/(.*))?$/i
Вот и всё.

Чего не хватает:
1) Проверки что в домене есть хотя бы одна буква кроме точки или тире
2) Лимит на количество цифр в порте.


Спасибо вам за уделённое время и удачных экспериментов. Если дело пойдёт - будет вам вторая часть.
__________________
Retry, Abort, Ignore? █
Intel Core i7-9700 4.70 Ghz; 64Gb; Nvidia RTX 3070
AMD Ryzen 7 3800X 4.3Ghz; 64Gb; Nvidia 1070Ti
AMD Ryzen 7 1700X 3.4Ghz; 8Gb; AMD RX 570
AMD Athlon II 2.6Ghz; 8Gb; Nvidia GTX 750 Ti

Последний раз редактировалось Randomize, 14.08.2014 в 15:12.
(Offline)
 
Ответить с цитированием
Эти 22 пользователя(ей) сказали Спасибо Randomize за это полезное сообщение:
.Squid (05.11.2011), ABTOMAT (04.11.2011), baton4ik (04.11.2011), den (05.11.2011), Лис (21.02.2015), Halk-DS (02.10.2013), Harter (24.03.2013), impersonalis (05.11.2011), L.D.M.T. (06.11.2011), Leo_ind (27.01.2012), mingw (16.03.2019), moka (05.11.2011), Mr_F_ (27.06.2012), Nerd (06.04.2014), pax (04.11.2011), Reks888 (04.11.2011), SBJoker (05.11.2011), St_AnGer (05.11.2011), Tadeus (27.06.2012), treycerok (14.04.2012), VotapilD (05.11.2011), Черный крыс (15.08.2013)