Regex for url validation with parts capturing

2019-02-24 02:59发布

问题:

Can a single regex be used to valdate urls and match all the parts, I have been working on one and what I have come up with so far is:

(?:(?P<scheme>[a-z]*?)://)?(?:(?P<username>.*?):?(?P<password>.*?)?@)?(?P<hostname>.*?)/(?:(?:(?P<path>.*?)\?)?(?P<file>.*?\.[a-z]{1,6})?(?:(?:(?P<query>.*?)#?)?(?P<fragment>.*?)?)?)?

however this does not work, it should match all of the following examples:

http://username:password@hostname.tld/path?arg=value#anchor
http://www.domain.com/
http://www.doamin.co.uk/
http://www.yahoo.com/
http://www.google.au/
https://username:password@domain.com/
ftp://user:password@domain.com/path/
https://www.blah1.subdoamin.doamin.tld/
domain.tld/#anchor
doamin.tld/?query=123
domain.co.uk/
domain.tld
http://www.domain.tld/index.php?var1=blah
http://www.domain.tld/path/to/index.ext
mailto://user@unkwndesign.com

and provide a named capture for all the components:

scheme eg. http https ftp ftps callto mailto and any other one not listed
username
password
hostname including subdomains, domainand tld
path eg /images/profile/
filename eg file.ext
query string eg. ?foo=bar&bar=foo
fragment eg. #anchor

With the hostname as the only mandatory field.

We can assume that this is coming from a form specificly asking for an url, and is not going to be used to find links in text.

回答1:

Modified version of mingfai's regular expression:

/^((?P<scheme>https?|ftp):\/)?\/?((?P<username>.*?)(:(?P<password>.*?)|)@)?(?P<hostname>[^:\/\s]+)(?P<port>:([^\/]*))?(?P<path>(\/\w+)*\/)(?P<filename>[-\w.]+[^#?\s]*)?(?P<query>\?([^#]*))?(?P<fragment>#(.*))?$/


回答2:

Can a single regex be used to valdate urls and match all the parts

No.

strager's regex is impressive, but at the end of the day it's less readable, maintainable and reliable than just using a proper URI parser. It necessarily rejects valid URIs and accepts strings that are not URIs, because the rules of formatting URIs cannot be fully expressed in a regex.

mailto://user@unkwndesign.com

There shouldn't be a '//' in a mailto URI. You can't tell what format the remainder (post-:) of the URI is going to be until you've read the scheme; many URI schemes do not conform to the credentials@host/path format. Best to accept only specific schemes where you know how to parse their URIs.