Obtendo partes de uma URL (Regex)

Dado o URL (linha única):
http://test.example.com/dir/subdir/file.html

Como posso extrair as seguintes partes usando expressões regulares:

  1. O subdomínio (teste)
  2. O domínio (example.com)
  3. O caminho sem o arquivo (/ dir / subdir /)
  4. O arquivo (file.html)
  5. O caminho com o arquivo (/dir/subdir/file.html)
  6. O URL sem o caminho ( http://test.example.com )
  7. (adicione qualquer outro que você acha que seria útil)

O regex deve funcionar corretamente, mesmo se eu inserir o seguinte URL:
http://example.example.com/example/example/example.html

Obrigado.

Percebo que estou atrasado para a festa, mas há uma maneira simples de deixar o navegador analisar um URL para você sem um regex:

 var a = document.createElement('a'); a.href = 'http://www.example.com:123/foo/bar.html?fox=trot#foo'; ['href','protocol','host','hostname','port','pathname','search','hash'].forEach(function(k) { console.log(k+':', a[k]); }); /*//Output: href: http://www.example.com:123/foo/bar.html?fox=trot#foo protocol: http: host: www.example.com:123 hostname: www.example.com port: 123 pathname: /foo/bar.html search: ?fox=trot hash: #foo */ 

Estou alguns anos atrasado para a festa, mas estou surpreso que ninguém tenha mencionado que a especificação do Uniform Resource Identifier tem uma seção sobre a análise de URIs com uma expressão regular . A expressão regular, escrita por Berners-Lee, et al., É:

 ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? 12 3 4 5 6 7 8 9 

Os números na segunda linha acima são apenas para auxiliar a legibilidade; eles indicam os pontos de referência para cada subexpressão (isto é, cada parêntese emparelhado). Nos referimos ao valor correspondente à subexpressão como $. Por exemplo, combinando a expressão acima para

http://www.ics.uci.edu/pub/ietf/uri/#Related

resulta nas seguintes correspondências de subexpressão:

 $1 = http: $2 = http $3 = //www.ics.uci.edu $4 = www.ics.uci.edu $5 = /pub/ietf/uri/ $6 =  $7 =  $8 = #Related $9 = Related 

Por que vale a pena, descobri que tinha que escaping das barras no JavaScript:

^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?

Eu encontrei a resposta mais votada (resposta do hometoast) não funciona perfeitamente para mim. Dois problemas:

  1. Não pode manipular o número da porta.
  2. A parte hash está quebrada.

O seguinte é uma versão modificada:

 ^((http[s]?|ftp):\/)?\/?([^:\/\s]+)(:([^\/]*))?((\/\w+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?$ 

A posição das peças é a seguinte:

 int SCHEMA = 2, DOMAIN = 3, PORT = 5, PATH = 6, FILE = 8, QUERYSTRING = 9, HASH = 12 

Editar postado por usuário anon:

 function getFileName(path) { return path.match(/^((http[s]?|ftp):\/)?\/?([^:\/\s]+)(:([^\/]*))?((\/[\w\/-]+)*\/)([\w\-\.]+[^#?\s]+)(\?([^#]*))?(#(.*))?$/i)[8]; } 

Eu precisava de uma Expressão regular para corresponder a todas as URLs e fiz esta:

 /(?:([^\:]*)\:\/\/)?(?:([^\:\@]*)(?:\:([^\@]*))?\@)?(?:([^\/\:]*)\.(?=[^\.\/\:]*\.[^\.\/\:]*))?([^\.\/\:]*)(?:\.([^\/\.\:]*))?(?:\:([0-9]*))?(\/[^\?#]*(?=.*?\/)\/)?([^\?#]*)?(?:\?([^#]*))?(?:#(.*))?/ 

Ele combina com todos os URLs, qualquer protocolo, até mesmo URLs como

 ftp://user:pass@www.cs.server.com:8080/dir1/dir2/file.php?param1=value1#hashtag 

O resultado (em JavaScript) é assim:

 ["ftp", "user", "pass", "www.cs", "server", "com", "8080", "/dir1/dir2/", "file.php", "param1=value1", "hashtag"] 

Uma URL como

 mailto://admin@www.cs.server.com 

se parece com isso:

 ["mailto", "admin", undefined, "www.cs", "server", "com", undefined, undefined, undefined, undefined, undefined] 

Eu estava tentando resolver isso em javascript, que deve ser tratado por:

 var url = new URL('http://a:b@example.com:890/path/wah@t/foo.js?foo=bar&bingobang=&king=kong@kong.com#foobar/bing/bo@ng?bang'); 

já que (no Chrome, pelo menos) ele analisa:

 { "hash": "#foobar/bing/bo@ng?bang", "search": "?foo=bar&bingobang=&king=kong@kong.com", "pathname": "/path/wah@t/foo.js", "port": "890", "hostname": "example.com", "host": "example.com:890", "password": "b", "username": "a", "protocol": "http:", "origin": "http://example.com:890", "href": "http://a:b@example.com:890/path/wah@t/foo.js?foo=bar&bingobang=&king=kong@kong.com#foobar/bing/bo@ng?bang" } 

No entanto, isso não é cross browser ( https://developer.mozilla.org/en-US/docs/Web/API/URL ), então eu montei as partes juntas como acima:

 ^(?:(?:(([^:\/#\?]+:)?(?:(?:\/\/)(?:(?:(?:([^:@\/#\?]+)(?:\:([^:@\/#\?]*))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((?:\/?(?:[^\/\?#]+\/+)*)(?:[^\?#]*)))?(\?[^#]+)?)(#.*)? 

O crédito por este regex vai para https://gist.github.com/rpflorence que postou este jsperf http://jsperf.com/url-parsing (originalmente encontrado aqui: https://gist.github.com/jlong/2428561 # comment-310066 ) que surgiu com o regex em que isso foi originalmente baseado.

As peças estão nesta ordem:

 var keys = [ "href", // http://user:pass@host.com:81/directory/file.ext?query=1#anchor "origin", // http://user:pass@host.com:81 "protocol", // http: "username", // user "password", // pass "host", // host.com:81 "hostname", // host.com "port", // 81 "pathname", // /directory/file.ext "search", // ?query=1 "hash" // #anchor ]; 

Há também uma pequena biblioteca que o envolve e fornece parâmetros de consulta:

https://github.com/sadams/lite-url (também disponível no bower)

Se você tiver uma melhoria, por favor, crie uma solicitação pull com mais testes e eu vou aceitar e mesclar com agradecimentos.

Esta não é uma resposta direta, mas a maioria das bibliotecas da Web tem uma function que realiza essa tarefa. A function é freqüentemente chamada de algo semelhante ao CrackUrl . Se tal function existir, use-a, é quase garantido que ela seja mais confiável e mais eficiente do que qualquer código feito a mão.

subdomínio e domínio são difíceis porque o subdomínio pode ter várias partes, assim como o domínio de nível superior, http://sub1.sub2.domain.co.uk/

  the path without the file : http://[^/]+/((?:[^/]+/)*(?:[^/]+$)?) the file : http://[^/]+/(?:[^/]+/)*((?:[^/.]+\.)+[^/.]+)$ the path with the file : http://[^/]+/(.*) the URL without the path : (http://[^/]+/) 

(Markdown não é muito amigável para regexes)

Essa versão aprimorada deve funcionar de forma confiável como um analisador.

  // Applies to URI, not just URL or URN: // http://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Relationship_to_URL_and_URN // // http://labs.apache.org/webarch/uri/rfc/rfc3986.html#regexp // // (?:([^:/?#]+):)?(?://([^/?#]*))?([^?#]*)(?:\?([^#]*))?(?:#(.*))? // // http://en.wikipedia.org/wiki/URI_scheme#Generic_syntax // // $@ matches the entire uri // $1 matches scheme (ftp, http, mailto, mshelp, ymsgr, etc) // $2 matches authority (host, user:pwd@host, etc) // $3 matches path // $4 matches query (http GET REST api, etc) // $5 matches fragment (html anchor, etc) // // Match specific schemes, non-optional authority, disallow white-space so can delimit in text, and allow 'www.' w/o scheme // Note the schemes must match ^[^\s|:/?#]+(?:\|[^\s|:/?#]+)*$ // // (?:()(www\.[^\s/?#]+\.[^\s/?#]+)|(schemes)://([^\s/?#]*))([^\s?#]*)(?:\?([^\s#]*))?(#(\S*))? // // Validate the authority with an orthogonal RegExp, so the RegExp above won't fail to match any valid urls. function uriRegExp( flags, schemes/* = null*/, noSubMatches/* = false*/ ) { if( !schemes ) schemes = '[^\\s:\/?#]+' else if( !RegExp( /^[^\s|:\/?#]+(?:\|[^\s|:\/?#]+)*$/ ).test( schemes ) ) throw TypeError( 'expected URI schemes' ) return noSubMatches ? new RegExp( '(?:www\\.[^\\s/?#]+\\.[^\\s/?#]+|' + schemes + '://[^\\s/?#]*)[^\\s?#]*(?:\\?[^\\s#]*)?(?:#\\S*)?', flags ) : new RegExp( '(?:()(www\\.[^\\s/?#]+\\.[^\\s/?#]+)|(' + schemes + ')://([^\\s/?#]*))([^\\s?#]*)(?:\\?([^\\s#]*))?(?:#(\\S*))?', flags ) } // http://en.wikipedia.org/wiki/URI_scheme#Official_IANA-registered_schemes function uriSchemesRegExp() { return 'about|callto|ftp|gtalk|http|https|irc|ircs|javascript|mailto|mshelp|sftp|ssh|steam|tel|view-source|ymsgr' } 

Tente o seguinte:

 ^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)? 

Suporta HTTP / FTP, subdomínios, pastas, arquivos etc.

Eu encontrei de uma rápida pesquisa no google:

http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx

 /^((?Phttps?|ftp):\/)?\/?((?P.*?)(:(?P.*?)|)@)?(?P[^:\/\s]+)(?P:([^\/]*))?(?P(\/\w+)*\/)(?P[-\w.]+[^#?\s]*)?(?P\?([^#]*))?(?P#(.*))?$/ 

Da minha resposta em uma pergunta semelhante . Funciona melhor do que alguns dos outros mencionados porque eles tinham alguns bugs (como não suportar nome de usuário / senha, não suportando nomes de arquivos de um único caractere, identificadores de fragments sendo quebrados).

Proponha uma solução muito mais legível (em Python, mas aplica-se a qualquer regex):

 def url_path_to_dict(path): pattern = (r'^' r'((?P.+?)://)?' r'((?P.+?)(:(?P.*?))?@)?' r'(?P.*?)' r'(:(?P\d+?))?' r'(?P/.*?)?' r'(?P[?].*?)?' r'$' ) regex = re.compile(pattern) m = regex.match(path) d = m.groupdict() if m is not None else None return d def main(): print url_path_to_dict('http://example.example.com/example/example/example.html') 

Impressões:

 { 'host': 'example.example.com', 'user': None, 'path': '/example/example/example.html', 'query': None, 'password': None, 'port': None, 'schema': 'http' } 

Você pode obter todos os caminhos http / https, host, port, bem como consultar usando o object Uri no .NET. apenas a tarefa difícil é dividir o host em subdomínio, nome de domínio e TLD.

Não há um padrão para fazer isso e não pode simplesmente usar a análise de string ou RegEx para produzir o resultado correto. No início, estou usando a function RegEx, mas nem toda URL pode analisar o subdomínio corretamente. A maneira prática é usar uma lista de TLDs. Depois que um TLD para um URL é definido, a parte esquerda é domínio e o restante é subdomínio.

No entanto, a lista precisa mantê-lo, uma vez que novos TLDs são possíveis. O momento atual que eu sei é que publicsuffix.org mantém a lista mais recente e você pode usar as ferramentas domainname-parser do google code para analisar a lista de sufixos públicos e obter o subdomínio, domínio e TLD facilmente usando o object DomainName: domainName.SubDomain, domainName Domínio e domainName.TLD.

Isso também ajuda: obtenha o subdomínio de um URL

CaLMeLaNN

Infelizmente, isso não funciona com algumas URLs. Veja, por exemplo, este: http://www.example.org/&value=329

Nem o valor é = 329

Ou mesmo sem parâmetros (uma URL simples)!

Eu entendo que o regex está esperando algum URL seriamente complexo / longo, mas ele deve ser capaz de trabalhar em outros simples também, estou certo?

Aqui está um que está completo e não depende de nenhum protocolo.

 function getServerURL(url) { var m = url.match("(^(?:(?:.*?)?//)?[^/?#;]*)"); console.log(m[1]) // Remove this return m[1]; } getServerURL("http://dev.test.se") getServerURL("http://dev.test.se/") getServerURL("//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js") getServerURL("//") getServerURL("www.dev.test.se/sdas/dsads") getServerURL("www.dev.test.se/") getServerURL("www.dev.test.se?abc=32") getServerURL("www.dev.test.se#abc") getServerURL("//dev.test.se?sads") getServerURL("http://www.dev.test.se#321") getServerURL("http://localhost:8080/sads") getServerURL("https://localhost:8080?sdsa") 

Impressões

 http://dev.test.se http://dev.test.se //ajax.googleapis.com // www.dev.test.se www.dev.test.se www.dev.test.se www.dev.test.se //dev.test.se http://www.dev.test.se http://localhost:8080 https://localhost:8080 

Nenhum dos acima funcionou para mim. Aqui está o que acabei usando:

 /^(?:((?:https?|s?ftp):)\/\/)([^:\/\s]+)(?::(\d*))?(?:\/([^\s?#]+)?([?][^?#]*)?(#.*)?)?/ 

Eu gosto do regex que foi publicado em “Javascript: The Good Parts”. Não é muito curto nem muito complexo. Esta página no github também possui o código JavaScript que a utiliza. Mas pode ser adaptado para qualquer idioma. https://gist.github.com/voodooGQ/4057330

Java oferece uma class de URL que fará isso. Objetos de URL de consulta.

Em uma nota lateral, o PHP oferece parse_url () .

Eu recomendaria não usar o regex. Uma chamada de API como WinHttpCrackUrl () é menos propensa a erros.

http://msdn.microsoft.com/pt-br/library/aa384092%28VS.85%29.aspx

Usando o http://www.fileformat.info/tool/regex.htm, o regex do hometoast funciona muito bem.

Mas aqui está o acordo, eu quero usar diferentes padrões de regex em diferentes situações no meu programa.

Por exemplo, eu tenho esse URL e tenho uma enumeração que lista todos os URLs suportados no meu programa. Cada object na enumeração tem um método getRegexPattern que retorna o padrão regex, que será usado para comparar com um URL. Se o padrão de expressão regular retornar true, então sei que essa URL é suportada pelo meu programa. Portanto, cada enumeração tem sua própria regex, dependendo de onde ela deve aparecer dentro da URL.

A sugestão do Hometoast é ótima, mas no meu caso, acho que não ajudaria (a menos que eu copie, cole o mesmo regex em todas as enumerações).

É por isso que eu queria a resposta para dar o regex para cada situação separadamente. Embora +1 para hometoast. 😉

Eu sei que você está afirmando que é agnóstico em relação a isso, mas você pode nos dizer o que está usando apenas para sabermos quais resources de regex você tem?

Se você tiver os resources para não capturar correspondências, poderá modificar a expressão do hometoast para que as subexpressões que não estão interessadas em capturar sejam configuradas assim:

(?:SOMESTUFF)

Você ainda teria que copiar e colar (e modificar ligeiramente) o Regex em vários lugares, mas isso faz sentido – você não está apenas verificando se a subexpressão existe, mas se ela existe como parte de um URL . Usar o modificador de não captura para subexpressões pode fornecer o que você precisa e nada mais, o que, se eu estiver lendo corretamente, é o que você quer.

Assim como uma nota pequena e pequena, a expressão do hometoast não precisa colocar parênteses em volta do ‘s’ para ‘https’, já que ele tem apenas um caractere lá. Os quantificadores quantificam o único caractere (ou class de caractere ou subexpressão) que os precede diretamente. Assim:

https?

combinaria ‘http’ ou ‘https’ bem.

regexp para obter o caminho da URL sem o arquivo.

url = ‘ http: // domínio / dir1 / dir2 / algum arquivo’ url.scan (/ ^ (http: // [^ /] +) ((?: / [^ /] +) + (? = /)) ? /? (?: [^ /] +)? $ / i) .to_s

Pode ser útil para adicionar um caminho relativo a este URL.

 String s = "https://www.thomas-bayer.com/axis2/services/BLZService?wsdl"; String regex = "(^http.?://)(.*?)([/\\?]{1,})(.*)"; System.out.println("1: " + s.replaceAll(regex, "$1")); System.out.println("2: " + s.replaceAll(regex, "$2")); System.out.println("3: " + s.replaceAll(regex, "$3")); System.out.println("4: " + s.replaceAll(regex, "$4")); 

Fornecerá a seguinte saída:
1: https: //
2: http://www.thomas-bayer.com
3: /
4: axis2 / services / BLZService? Wsdl

Se você alterar o URL para
String s = ” https://www.thomas-bayer.com?wsdl=qwerwer&ttt=888 “; a saída será a seguinte:
1: https: //
2: http://www.thomas-bayer.com
3:?
4: wsdl = qwerwer & ttt = 888

apreciar..
Yosi Lev

O regex para fazer a análise completa é bastante horrível. Eu incluí as referências anteriores para legibilidade e dividi cada parte em linhas separadas, mas ainda assim:

 ^(?:(?P\w+(?=:\/\/))(?::\/\/))? (?:(?P(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::(?P[0-9]+))?)\/)? (?:(?P(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)? (?P(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+) (?:\?(?P(?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))? (?:#(?P.*))?$ 

O que exige que seja tão detalhado é que, exceto pelo protocolo ou pela porta, qualquer uma das partes pode conter entidades HTML, o que torna o delineamento do fragment bastante complicado. Então, nos últimos casos – o host, caminho, arquivo, querystring e fragment, nós permitimos qualquer entidade html ou qualquer caractere que não seja um ? ou # . O regex para uma entidade html se parece com isto:

 $htmlentity = "&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);" 

Quando isso é extraído (usei uma syntax de bigode para representá-lo), ele se torna um pouco mais legível:

 ^(?:(?P(?:ht|f)tps?|\w+(?=:\/\/))(?::\/\/))? (?:(?P(?:{{htmlentity}}|[^\/?#:])+(?::(?P[0-9]+))?)\/)? (?:(?P(?:{{htmlentity}}|[^?#])+)\/)? (?P(?:{{htmlentity}}|[^?#])+) (?:\?(?P(?:{{htmlentity}};|[^#])+))? (?:#(?P.*))?$ 

Em JavaScript, é claro, você não pode usar backreferences nomeadas, então o regex se torna

 ^(?:(\w+(?=:\/\/))(?::\/\/))?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^\/?#:]+)(?::([0-9]+))?)\/)?(?:((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)\/)?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^?#])+)(?:\?((?:(?:&(?:amp|apos|gt|lt|nbsp|quot|bull|hellip|[lr][ds]quo|[mn]dash|permil|\#[1-9][0-9]{1,3}|[A-Za-z][0-9A-Za-z]+);)|[^#])+))?(?:#(.*))?$ 

e em cada correspondência, o protocolo é \1 , o host é \2 , a porta é \3 , o caminho \4 , o arquivo \5 , o querystring \6 e o fragment \7 .

Eu tentei alguns desses que não cobriam as minhas necessidades, especialmente os mais votados que não pegavam um URL sem um caminho ( http://example.com/ )

também a falta de nomes de grupo tornou inutilizável em ansible (ou talvez minhas habilidades jinja2 estão faltando).

então esta é minha versão ligeiramente modificada com a fonte sendo a versão mais votada aqui:

 ^((?Phttp[s]?|ftp):\/)?\/?(?P[^:\/\s]+)(?P((\/\w+)*\/)([\w\-\.]+[^#?\s]+))*(.*)?(#[\w\-]+)?$ 
 //USING REGEX /** * Parse URL to get information * * @param url the URL string to parse * @return parsed the URL parsed or null */ var UrlParser = function (url) { "use strict"; var regx = /^(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/, matches = regx.exec(url), parser = null; if (null !== matches) { parser = { href : matches[0], withoutHash : matches[1], url : matches[2], origin : matches[3], protocol : matches[4], protocolseparator : matches[5], credhost : matches[6], cred : matches[7], user : matches[8], pass : matches[9], host : matches[10], hostname : matches[11], port : matches[12], pathname : matches[13], segment1 : matches[14], segment2 : matches[15], search : matches[16], hash : matches[17] }; } return parser; }; var parsedURL=UrlParser(url); console.log(parsedURL);