Проверка PHP / регулярное выражение для URL
Я искал простое регулярное выражение для URL, у кого-нибудь есть один удобный, который хорошо работает? Я не нашел ни одного с классами проверки Zend framework и видел несколько реализаций.
спасибо
20 ответов:
я использовал это на нескольких проектах, я не думаю, что я столкнулся с проблемами, но я уверен, что это не исчерпывающий:
$text = preg_replace( '#((https?|ftp)://(\S*?\.\S*?))([\s)\[\]{},;"\':<]|\.\s|$)#i', "'<a href=\"\" target=\"_blank\"></a>'", $text );
большая часть случайного мусора в конце-это иметь дело с такими ситуациями, как
http://domain.com.
в предложении (чтобы не совпадать с конечным периодом). Я уверен, что это можно было бы очистить, но так как это сработало. Я более или менее просто скопировал его из проекта в проект.
использовать
filter_var()
функция для проверки того, является ли строка URL или нет:var_dump(filter_var('example.com', FILTER_VALIDATE_URL));
Это плохая практика, чтобы использовать регулярные выражения, когда не надо.
EDIT: будьте внимательны, это решение не Юникод-безопасный и не межсайтового скриптинга. Если вам нужна сложная проверка, может быть, лучше поискать где-то еще.
согласно руководству PHP-parse_url должен не используется для проверки URL-адреса.
к сожалению, похоже, что
filter_var('example.com', FILTER_VALIDATE_URL)
не работает лучше.и
parse_url()
иfilter_var()
будет передавать искаженные URL-адреса, такие какhttp://...
поэтому в данном случае - выражение и лучший способ.
на всякий случай, если вы хотите знать, если url действительно существует:
function url_exist($url){//se passar a URL existe $c=curl_init(); curl_setopt($c,CURLOPT_URL,$url); curl_setopt($c,CURLOPT_HEADER,1);//get the header curl_setopt($c,CURLOPT_NOBODY,1);//and *only* get the header curl_setopt($c,CURLOPT_RETURNTRANSFER,1);//get the response as a string from curl_exec(), rather than echoing it curl_setopt($c,CURLOPT_FRESH_CONNECT,1);//don't use a cached version of the url if(!curl_exec($c)){ //echo $url.' inexists'; return false; }else{ //echo $url.' exists'; return true; } //$httpcode=curl_getinfo($c,CURLINFO_HTTP_CODE); //return ($httpcode<400); }
по состоянию на Джон Грубер (Дерзкий Огненный Шар):
регулярное выражение:
(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))
используя в функции preg_match():
preg_match("/(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'\".,<>?«»“”‘’]))/", $url)
вот расширенный шаблон регулярных выражений (с комментариями):
(?xi) \b ( # Capture 1: entire matched URL (?: https?:// # http or https protocol | # or www\d{0,3}[.] # "www.", "www1.", "www2." … "www999." | # or [a-z0-9.\-]+[.][a-z]{2,4}/ # looks like domain name followed by a slash ) (?: # One or more: [^\s()<>]+ # Run of non-space, non-()<> | # or \(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels )+ (?: # End with: \(([^\s()<>]+|(\([^\s()<>]+\)))*\) # balanced parens, up to 2 levels | # or [^\s`!()\[\]{};:'".,<>?«»“”‘’] # not a space or one of these punct chars ) )
для более подробной информации, пожалуйста, посмотрите на: http://daringfireball.net/2010/07/improved_regex_for_matching_urls
Я не думаю, что использование регулярных выражений является разумной вещью в этом случае. Невозможно сопоставить все возможности, и даже если вы это сделали, все равно есть шанс, что url просто не существует.
вот очень простой способ проверить, если url действительно существует и читается:
if (preg_match("#^https?://.+#", $link) and @fopen($link,"r")) echo "OK";
(если нет
preg_match
тогда это также подтвердит все имена файлов на вашем сервере)
function validateURL($URL) { $pattern_1 = "/^(http|https|ftp):\/\/(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i"; $pattern_2 = "/^(www)((\.[A-Z0-9][A-Z0-9_-]*)+.(com|org|net|dk|at|us|tv|info|uk|co.uk|biz|se)$)(:(\d+))?\/?/i"; if(preg_match($pattern_1, $URL) || preg_match($pattern_2, $URL)){ return true; } else{ return false; } }
я использовал это с хорошим успехом - я не помню, где я получил его от
$pattern = "/\b(?:(?:https?|ftp):\/\/|www\.)[-a-z0-9+&@#\/%?=~_|!:,.;]*[-a-z0-9+&@#\/%=~_|]/i";
и вот ваш ответ =) попробуйте сломать его, вы не можете!!!
function link_validate_url($text) { $LINK_DOMAINS = 'aero|arpa|asia|biz|com|cat|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|mobi|local'; $LINK_ICHARS_DOMAIN = (string) html_entity_decode(implode("", array( // @TODO completing letters ... "æ", // æ "Æ", // Æ "À", // À "à", // à "Á", // Á "á", // á "Â", //  "â", // â "å", // å "Å", // Å "ä", // ä "Ä", // Ä "Ç", // Ç "ç", // ç "Ð", // Ð "ð", // ð "È", // È "è", // è "É", // É "é", // é "Ê", // Ê "ê", // ê "Ë", // Ë "ë", // ë "Î", // Î "î", // î "Ï", // Ï "ï", // ï "ø", // ø "Ø", // Ø "ö", // ö "Ö", // Ö "Ô", // Ô "ô", // ô "Õ", // Õ "õ", // õ "Œ", // Œ "œ", // œ "ü", // ü "Ü", // Ü "Ù", // Ù "ù", // ù "Û", // Û "û", // û "Ÿ", // Ÿ "ÿ", // ÿ "Ñ", // Ñ "ñ", // ñ "þ", // þ "Þ", // Þ "ý", // ý "Ý", // Ý "¿", // ¿ )), ENT_QUOTES, 'UTF-8'); $LINK_ICHARS = $LINK_ICHARS_DOMAIN . (string) html_entity_decode(implode("", array( "ß", // ß )), ENT_QUOTES, 'UTF-8'); $allowed_protocols = array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'mailto', 'irc', 'ssh', 'sftp', 'webcal'); // Starting a parenthesis group with (?: means that it is grouped, but is not captured $protocol = '((?:'. implode("|", $allowed_protocols) .'):\/\/)'; $authentication = "(?:(?:(?:[\w\.\-\+!$&'\(\)*\+,;=" . $LINK_ICHARS . "]|%[0-9a-f]{2})+(?::(?:[\w". $LINK_ICHARS ."\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})*)?)?@)"; $domain = '(?:(?:[a-z0-9' . $LINK_ICHARS_DOMAIN . ']([a-z0-9'. $LINK_ICHARS_DOMAIN . '\-_\[\]])*)(\.(([a-z0-9' . $LINK_ICHARS_DOMAIN . '\-_\[\]])+\.)*('. $LINK_DOMAINS .'|[a-z]{2}))?)'; $ipv4 = '(?:[0-9]{1,3}(\.[0-9]{1,3}){3})'; $ipv6 = '(?:[0-9a-fA-F]{1,4}(\:[0-9a-fA-F]{1,4}){7})'; $port = '(?::([0-9]{1,5}))'; // Pattern specific to external links. $external_pattern = '/^'. $protocol .'?'. $authentication .'?('. $domain .'|'. $ipv4 .'|'. $ipv6 .' |localhost)'. $port .'?'; // Pattern specific to internal links. $internal_pattern = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]]+)"; $internal_pattern_file = "/^(?:[a-z0-9". $LINK_ICHARS ."_\-+\[\]\.]+)$/i"; $directories = "(?:\/[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'#!():;*@\[\]]*)*"; // Yes, four backslashes == a single backslash. $query = "(?:\/?\?([?a-z0-9". $LINK_ICHARS ."+_|\-\.~\/\\%=&,$'():;*@\[\]{} ]*))"; $anchor = "(?:#[a-z0-9". $LINK_ICHARS ."_\-\.~+%=&,$'():;*@\[\]\/\?]*)"; // The rest of the path for a standard URL. $end = $directories .'?'. $query .'?'. $anchor .'?'.'$/i'; $message_id = '[^@].*@'. $domain; $newsgroup_name = '(?:[0-9a-z+-]*\.)*[0-9a-z+-]*'; $news_pattern = '/^news:('. $newsgroup_name .'|'. $message_id .')$/i'; $user = '[a-zA-Z0-9'. $LINK_ICHARS .'_\-\.\+\^!#$%&*+\/\=\?\`\|\{\}~\'\[\]]+'; $email_pattern = '/^mailto:'. $user .'@'.'(?:'. $domain .'|'. $ipv4 .'|'. $ipv6 .'|localhost)'. $query .'?$/'; if (strpos($text, '<front>') === 0) { return false; } if (in_array('mailto', $allowed_protocols) && preg_match($email_pattern, $text)) { return false; } if (in_array('news', $allowed_protocols) && preg_match($news_pattern, $text)) { return false; } if (preg_match($internal_pattern . $end, $text)) { return false; } if (preg_match($external_pattern . $end, $text)) { return false; } if (preg_match($internal_pattern_file, $text)) { return false; } return true; }
Edit:
Как частота указал, что этот код был устаревшим с выпуском PHP 5.3.0 (2009-06-30) и должен использоваться соответствующим образом.
только мои два цента, но я разработал эту функцию и использую ее некоторое время с успехом. Он хорошо документирован и разделен, поэтому вы можете легко его изменить.
// Checks if string is a URL // @param string $url // @return bool function isURL($url = NULL) { if($url==NULL) return false; $protocol = '(http://|https://)'; $allowed = '([a-z0-9]([-a-z0-9]*[a-z0-9]+)?)'; $regex = "^". $protocol . // must include the protocol '(' . $allowed . '{1,63}\.)+'. // 1 or several sub domains with a max of 63 chars '[a-z]' . '{2,6}'; // followed by a TLD if(eregi($regex, $url)==true) return true; else return false; }
function is_valid_url ($url="") { if ($url=="") { $url=$this->url; } $url = @parse_url($url); if ( ! $url) { return false; } $url = array_map('trim', $url); $url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port']; $path = (isset($url['path'])) ? $url['path'] : ''; if ($path == '') { $path = '/'; } $path .= ( isset ( $url['query'] ) ) ? "?$url[query]" : ''; if ( isset ( $url['host'] ) AND $url['host'] != gethostbyname ( $url['host'] ) ) { if ( PHP_VERSION >= 5 ) { $headers = get_headers("$url[scheme]://$url[host]:$url[port]$path"); } else { $fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30); if ( ! $fp ) { return false; } fputs($fp, "HEAD $path HTTP/1.1\r\nHost: $url[host]\r\n\r\n"); $headers = fread ( $fp, 128 ); fclose ( $fp ); } $headers = ( is_array ( $headers ) ) ? implode ( "\n", $headers ) : $headers; return ( bool ) preg_match ( '#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers ); } return false; }
вдохновение в этом вопросе .NET StackOverflow и в этой ссылочной статье из этого вопроса есть этот валидатор URI (URI означает, что он проверяет как URL, так и URN).
if( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\/\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\3)@)?(?=(\[[0-9A-F:.]{2,}\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\5(?::(?=(\d*))\6)?)(\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\8)?|(\/?(?!\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\10)?)(?:\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\12)?$/i", $uri ) ) { throw new \RuntimeException( "URI has not a valid format." ); }
я успешно проверил эту функцию внутри объекта ValueObject, который я сделал с именем
Uri
и испытаныUriTest
.UriTest.php (содержит допустимые и недопустимые случаи для URL-адресов и урн)
<?php declare( strict_types = 1 ); namespace XaviMontero\ThrasherPortage\Tests\Tour; use XaviMontero\ThrasherPortage\Tour\Uri; class UriTest extends \PHPUnit_Framework_TestCase { private $sut; public function testCreationIsOfProperClassWhenUriIsValid() { $sut = new Uri( 'http://example.com' ); $this->assertInstanceOf( 'XaviMontero\ThrasherPortage\Tour\Uri', $sut ); } /** * @dataProvider urlIsValidProvider * @dataProvider urnIsValidProvider */ public function testGetUriAsStringWhenUriIsValid( string $uri ) { $sut = new Uri( $uri ); $actual = $sut->getUriAsString(); $this->assertInternalType( 'string', $actual ); $this->assertEquals( $uri, $actual ); } public function urlIsValidProvider() { return [ [ 'http://example-server' ], [ 'http://example.com' ], [ 'http://example.com/' ], [ 'http://subdomain.example.com/path/?parameter1=value1¶meter2=value2' ], [ 'random-protocol://example.com' ], [ 'http://example.com:80' ], [ 'http://example.com?no-path-separator' ], [ 'http://example.com/pa%20th/' ], [ 'ftp://example.org/resource.txt' ], [ 'file://../../../relative/path/needs/protocol/resource.txt' ], [ 'http://example.com/#one-fragment' ], [ 'http://example.edu:8080#one-fragment' ], ]; } public function urnIsValidProvider() { return [ [ 'urn:isbn:0-486-27557-4' ], [ 'urn:example:mammal:monotreme:echidna' ], [ 'urn:mpeg:mpeg7:schema:2001' ], [ 'urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ], [ 'rare-urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66' ], [ 'urn:FOO:a123,456' ] ]; } /** * @dataProvider urlIsNotValidProvider * @dataProvider urnIsNotValidProvider */ public function testCreationThrowsExceptionWhenUriIsNotValid( string $uri ) { $this->expectException( 'RuntimeException' ); $this->sut = new Uri( $uri ); } public function urlIsNotValidProvider() { return [ [ 'only-text' ], [ 'http//missing.colon.example.com/path/?parameter1=value1¶meter2=value2' ], [ 'missing.protocol.example.com/path/' ], [ 'http://example.com\bad-separator' ], [ 'http://example.com|bad-separator' ], [ 'ht tp://example.com' ], [ 'http://exampl e.com' ], [ 'http://example.com/pa th/' ], [ '../../../relative/path/needs/protocol/resource.txt' ], [ 'http://example.com/#two-fragments#not-allowed' ], [ 'http://example.edu:portMustBeANumber#one-fragment' ], ]; } public function urnIsNotValidProvider() { return [ [ 'urn:mpeg:mpeg7:sch ema:2001' ], [ 'urn|mpeg:mpeg7:schema:2001' ], [ 'urn?mpeg:mpeg7:schema:2001' ], [ 'urn%mpeg:mpeg7:schema:2001' ], [ 'urn#mpeg:mpeg7:schema:2001' ], ]; } }
Uri.php (значение Объект)
<?php declare( strict_types = 1 ); namespace XaviMontero\ThrasherPortage\Tour; class Uri { /** @var string */ private $uri; public function __construct( string $uri ) { $this->assertUriIsCorrect( $uri ); $this->uri = $uri; } public function getUriAsString() { return $this->uri; } private function assertUriIsCorrect( string $uri ) { // https://stackoverflow.com/questions/30847/regex-to-validate-uris // http://snipplr.com/view/6889/regular-expressions-for-uri-validationparsing/ if( ! preg_match( "/^([a-z][a-z0-9+.-]*):(?:\/\/((?:(?=((?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*))(\3)@)?(?=(\[[0-9A-F:.]{2,}\]|(?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*))\5(?::(?=(\d*))\6)?)(\/(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\8)?|(\/?(?!\/)(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*))\10)?)(?:\?(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\11)?(?:#(?=((?:[a-z0-9-._~!$&'()*+,;=:@\/?]|%[0-9A-F]{2})*))\12)?$/i", $uri ) ) { throw new \RuntimeException( "URI has not a valid format." ); } } }
Запуск UnitTests
есть 65 утверждений в 46 тестах. внимание: есть 2 поставщика данных для допустимых и еще 2 для недопустимых выражений. Один для URL-адресов, а другой для урн. Если вы используете версию PhpUnit версии v5. 6* или более ранней, то вам необходимо объединить два поставщика данных в один.
xavi@bromo:~/custom_www/hello-trip/mutant-migrant$ vendor/bin/phpunit PHPUnit 5.7.3 by Sebastian Bergmann and contributors. .............................................. 46 / 46 (100%) Time: 82 ms, Memory: 4.00MB OK (46 tests, 65 assertions)
покрытия кода
в этом примере URI есть 100% покрытия кода контролер.
хорошо, так что это немного сложнее, чем простое регулярное выражение, но оно позволяет использовать различные типы URL-адресов.
примеры:
- google.com
- www.microsoft.com/
- http://www.yahoo.com/
- https://www.bandcamp.com/artist/#! кто-то особенный!
все что должно быть помечен как действительный.
function is_valid_url($url) { // First check: is the url just a domain name? (allow a slash at the end) $_domain_regex = "|^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(\.[A-Za-z]{2,})/?$|"; if (preg_match($_domain_regex, $url)) { return true; } // Second: Check if it's a url with a scheme and all $_regex = '#^([a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))$#'; if (preg_match($_regex, $url, $matches)) { // pull out the domain name, and make sure that the domain is valid. $_parts = parse_url($url); if (!in_array($_parts['scheme'], array( 'http', 'https' ))) return false; // Check the domain using the regex, stops domains like "-example.com" passing through if (!preg_match($_domain_regex, $_parts['host'])) return false; // This domain looks pretty valid. Only way to check it now is to download it! return true; } return false; }
обратите внимание, что существует проверка in_array для протоколы, которые вы хотите разрешить (в настоящее время только http и https находятся в этом списке).
var_dump(is_valid_url('google.com')); // true var_dump(is_valid_url('google.com/')); // true var_dump(is_valid_url('http://google.com')); // true var_dump(is_valid_url('http://google.com/')); // true var_dump(is_valid_url('https://google.com')); // true
регулярное выражение Питера не выглядит правильным для меня по многим причинам. Он позволяет использовать все виды специальных символов в доменном имени и не тестирует много.
функция Фрэнки выглядит хорошо для меня, и вы можете построить хорошее регулярное выражение из компонентов, если вам не нужна функция, например:
^(http://|https://)(([a-z0-9]([-a-z0-9]*[a-z0-9]+)?){1,63}\.)+[a-z]{2,6}
непроверенные, но я думаю, что должно работать.
кроме того, ответ Оуэна тоже не выглядит 100%. Я взял доменную часть регулярного выражения и протестировал его на тестере регулярных выражений инструмент http://erik.eae.net/playground/regexp/regexp.html
Я поставил следующую строку:
(\S*?\.\S*?)
В разделе "регулярные выражения" и следующая строка:
-hello.com
В разделе "пример текста".
результат позволил минусовой символ через. Потому что \S означает любой символ, не являющийся пробелом.
обратите внимание, что регулярное выражение от Фрэнки обрабатывает минус, потому что у него есть эта часть для первый символ:
[a-z0-9]
который не позволит минус или любой другой специальный символ.
вот как я это сделал. Но я хочу отметить, что я не так уверен в регулярном выражении. Но это должно сработать ты:)
$pattern = "#((http|https)://(\S*?\.\S*?))(\s|\;|\)|\]|\[|\{|\}|,|”|\"|'|:|\<|$|\.\s)#i"; $text = preg_replace_callback($pattern,function($m){ return "<a href=\"$m[1]\" target=\"_blank\">$m[1]</a>$m[4]"; }, $text);
таким образом, вам не понадобится маркер eval на вашем шаблоне.
надеюсь, что это помогает :)
вот простой класс для проверка URL используя регулярное выражение, а затем перекрестные ссылки на домен против популярных серверов RBL (списки черных дыр в реальном времени):
установка:
require 'URLValidation.php';
использование:
require 'URLValidation.php'; $urlVal = new UrlValidation(); //Create Object Instance
добавить URL в качестве параметра
domain()
метод и проверьте возврат.$urlArray = ['http://www.bokranzr.com/test.php?test=foo&test=dfdf', 'https://en-gb.facebook.com', 'https://www.google.com']; foreach ($urlArray as $k=>$v) { echo var_dump($urlVal->domain($v)) . ' URL: ' . $v . '<br>'; }
выход:
bool(false) URL: http://www.bokranzr.com/test.php?test=foo&test=dfdf bool(true) URL: https://en-gb.facebook.com bool(true) URL: https://www.google.com
как вы можете видеть выше, www.bokranzr.com есть указан как вредоносный сайт через RBL, поэтому домен был возвращен как false.
для тех, кто разрабатывает с WordPress, просто используйте
esc_url_raw($url) === $url
для проверки URL (вот документация WordPress на
esc_url_raw
). Он обрабатывает URL-адреса намного лучше, чемfilter_var($url, FILTER_VALIDATE_URL)
, потому что и unicode и XSS-safe. (вот хорошая статья, в которой упоминаются все проблемы сfilter_var
).
Я нашел это, чтобы быть наиболее полезным для сопоставления URL-адрес..
^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
для этого есть собственная функция PHP:
$url = 'http://www.yoururl.co.uk/sub1/sub2/?param=1¶m2/'; if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) { // Wrong } else { // Valid }
возвращает отфильтрованные данные или FALSE, если фильтр не работает.
"/(http(s?):\/\/)([a-z0-9\-]+\.)+[a-z]{2,4}(\.[a-z]{2,4})*(\/[^ ]+)*/i"
(http (s?)://) означает http: / / или https://
([a-z0-9 -]+.)+ => 2.0 [a-z0-9-] означает любой символ a-z или любой знак 0-9 или ( -))
2.1 (+) means the character can be one or more ex: a1w, a9-,c559s, f) 2.2 \. is (.)sign 2.3. the (+) sign after ([a-z0-9\-]+\.) mean do 2.1,2.2,2.3 at least 1 time ex: abc.defgh0.ig, aa.b.ced.f.gh. also in case www.yyy.com 3.[a-z]{2,4} mean a-z at least 2 character but not more than 4 characters for check that there will not be the case ex: https://www.google.co.kr.asdsdagfsdfsf 4.(\.[a-z]{2,4})*(\/[^ ]+)* mean 4.1 \.[a-z]{2,4} means like number 3 but start with (.)sign 4.2 * means (\.[a-z]{2,4})can be use or not use never mind 4.3 \/ means \ 4.4 [^ ] means any character except blank 4.5 (+) means do 4.3,4.4,4.5 at least 1 times 4.6 (*) after (\/[^ ]+) mean use 4.3 - 4.5 or not use no problem use for case https://stackoverflow.com/posts/51441301/edit 5. when you use regex write in "/ /" so it come
" /(http (s?)://) ([a-z0-9 -]+.)+[a-z] {2,4}(.[a-z] {2,4})(/[^ ]+) / i"
6. almost forgot: letter i on the back mean ignore case of Big letter or small letter ex: A same as a, SoRRy same as sorry.
Примечание : извините за плохой английский. Моя страна не использует его хорошо.