URL parser: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
m (Add R solution)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(24 intermediate revisions by 18 users not shown)
Line 57:
:* &nbsp; <nowiki> urn:oasis:names:specification:docbook:dtd:xml:4.1.2 </nowiki>
<br><br>
 
=={{header|Ada}}==
{{libheader|AWS}}
<syntaxhighlight lang="ada">with Ada.Text_IO;
 
with AWS.URL;
with AWS.Parameters;
with AWS.Containers.Tables;
 
procedure URL_Parser is
 
procedure Parse (URL : in String) is
 
use AWS.URL, Ada.Text_IO;
use AWS.Containers.Tables;
 
procedure Put_Cond (Item : in String;
Value : in String;
When_Not : in String := "") is
begin
if Value /= When_Not then
Put (" "); Put (Item); Put_Line (Value);
end if;
end Put_Cond;
 
Obj : Object;
List : Table_Type;
begin
Put_Line ("Parsing " & URL);
 
Obj := Parse (URL);
List := Table_Type (AWS.Parameters.List'(AWS.URL.Parameters (Obj)));
 
Put_Cond ("Scheme: ", Protocol_Name (Obj));
Put_Cond ("Domain: ", Host (Obj));
Put_Cond ("Port: ", Port (Obj), When_Not => "0");
Put_Cond ("Path: ", Path (Obj));
Put_Cond ("File: ", File (Obj));
Put_Cond ("Query: ", Query (Obj));
Put_Cond ("Fragment: ", Fragment (Obj));
Put_Cond ("User: ", User (Obj));
Put_Cond ("Password: ", Password (Obj));
 
if List.Count /= 0 then
Put_Line (" Parameters:");
end if;
for Index in 1 .. List.Count loop
Put (" "); Put (Get_Name (List, N => Index));
Put (" "); Put ("'" & Get_Value (List, N => Index) & "'");
New_Line;
end loop;
New_Line;
end Parse;
 
begin
Parse ("foo://example.com:8042/over/there?name=ferret#nose");
Parse ("urn:example:animal:ferret:nose");
Parse ("jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true");
Parse ("ftp://ftp.is.co.za/rfc/rfc1808.txt");
Parse ("http://www.ietf.org/rfc/rfc2396.txt#header1");
Parse ("ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two");
Parse ("mailto:John.Doe@example.com");
Parse ("news:comp.infosystems.www.servers.unix");
Parse ("tel:+1-816-555-1212");
Parse ("telnet://192.0.2.16:80/");
Parse ("urn:oasis:names:specification:docbook:dtd:xml:4.1.2");
Parse ("ssh://alice@example.com");
Parse ("https://bob:pass@example.com/place");
Parse ("http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64");
end URL_Parser;</syntaxhighlight>
{{out}}
<pre>
Parsing foo://example.com:8042/over/there?name=ferret#nose
Scheme: foo
Domain: example.com
Port: 8042
Path: /over/
File: there
Query: name=ferret
Fragment: #nose
Parameters:
name 'ferret'
 
Parsing urn:example:animal:ferret:nose
Scheme: urn
File: example:animal:ferret:nose
 
Parsing jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
Scheme: jdbc
Path: mysql://test_user:ouupppssss@localhost:3306/
File: sakila
Query: profileSQL=true
Parameters:
profileSQL 'true'
 
Parsing ftp://ftp.is.co.za/rfc/rfc1808.txt
Scheme: ftp
Domain: ftp.is.co.za
Port: 21
Path: /rfc/
File: rfc1808.txt
 
Parsing http://www.ietf.org/rfc/rfc2396.txt#header1
Scheme: http
Domain: www.ietf.org
Port: 80
Path: /rfc/
File: rfc2396.txt
Fragment: #header1
 
Parsing ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
Scheme: ldap
Domain: 2001:db8::7
Path: /
File: c=GB
Query: objectClass=one&objectClass=two
Parameters:
objectClass 'one'
objectClass 'two'
 
Parsing mailto:John.Doe@example.com
Scheme: mailto
File: John.Doe@example.com
 
Parsing news:comp.infosystems.www.servers.unix
Scheme: news
File: comp.infosystems.www.servers.unix
 
Parsing tel:+1-816-555-1212
Scheme: tel
File: 1-816-555-1212
 
Parsing telnet://192.0.2.16:80/
Scheme: telnet
Domain: 192.0.2.16
Port: 80
Path: /
 
Parsing urn:oasis:names:specification:docbook:dtd:xml:4.1.2
Scheme: urn
File: oasis:names:specification:docbook:dtd:xml:4.1.2
 
Parsing ssh://alice@example.com
Scheme: ssh
Domain: alice@example.com
Path: /
 
Parsing https://bob:pass@example.com/place
Scheme: https
Domain: example.com
Port: 443
Path: /
File: place
User: bob
Password: pass
 
Parsing http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
Scheme: http
Domain: example.com
Port: 80
Path: /
Query: a=1&b=2%202&c=3&c=4&d=encoded
Parameters:
a '1'
b '2 2'
c '3'
c '4'
d 'encoded'
 
</pre>
 
=={{header|ALGOL 68}}==
Line 62 ⟶ 232:
Uses the URI parser here: [[URL_parser/URI_parser_ALGOL68]].
 
<langsyntaxhighlight lang="algol68">PR read "uriParser.a68" PR
 
PROC test uri parser = ( STRING uri )VOID:
Line 99 ⟶ 269:
; test uri parser( "https://bob:pass@example.com/place" )
; test uri parser( "http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64" )
END</langsyntaxhighlight>
{{out}}
<pre>
Line 177 ⟶ 347:
</pre>
 
=={{header|ArturoAppleScript}}==
 
Thanks to AppleScript's ability to interface with some of macOS's ObjectiveC API, the various components can simply be read off from an ''NSURLComponents'' object set from the URL text.
<lang arturo>url "foo://example.com:8042/over/there?name=ferret#nose"
 
<syntaxhighlight lang="applescript">use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
log $(getUrlComponents url)</lang>
use framework "Foundation"
 
on parseURLString(URLString)
{{out}}
set output to {URLString}
set indent to tab & "• "
set componentsObject to current application's class "NSURLComponents"'s componentsWithString:(URLString)
repeat with thisKey in {"scheme", "user", "password", "host", "port", "path", "query", "fragment"}
set thisValue to (componentsObject's valueForKey:(thisKey))
if (thisValue is not missing value) then set end of output to indent & thisKey & (" = " & thisValue)
end repeat
return join(output, linefeed)
end parseURLString
 
on join(listOfText, delimiter)
<pre>#{
set astid to AppleScript's text item delimiters
domain "example.com"
set AppleScript's text item delimiters to delimiter
fragment "nose"
set output to listOfText as text
password ""
set AppleScript's text item delimiters to astid
path "/over/there"
return output
port "8042"
end join
query #{
 
name "ferret"
-- Test code:
}
local output, URLString
scheme "foo"
set output to {}
user ""
repeat with URLString in {"foo://example.com:8042/over/there?name=ferret#nose", ¬
}</pre>
"urn:example:animal:ferret:nose", ¬
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true", ¬
"ftp://ftp.is.co.za/rfc/rfc1808.txt", ¬
"http://www.ietf.org/rfc/rfc2396.txt#header1", ¬
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two", ¬
"mailto:John.Doe@example.com", ¬
"news:comp.infosystems.www.servers.unix", ¬
"tel:+1-816-555-1212", ¬
"telnet://192.0.2.16:80/", ¬
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2", ¬
"http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"}
set end of output to parseURLString(URLString's contents)
end repeat
 
return join(output, linefeed & linefeed)</syntaxhighlight>
 
{{output}}
<syntaxhighlight lang="applescript">"foo://example.com:8042/over/there?name=ferret#nose
• scheme = foo
• host = example.com
• port = 8042
• path = /over/there
• query = name=ferret
• fragment = nose
 
urn:example:animal:ferret:nose
• scheme = urn
• path = example:animal:ferret:nose
 
jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
• scheme = jdbc
• path = mysql://test_user:ouupppssss@localhost:3306/sakila
• query = profileSQL=true
 
ftp://ftp.is.co.za/rfc/rfc1808.txt
• scheme = ftp
• host = ftp.is.co.za
• path = /rfc/rfc1808.txt
 
http://www.ietf.org/rfc/rfc2396.txt#header1
• scheme = http
• host = www.ietf.org
• path = /rfc/rfc2396.txt
• fragment = header1
 
ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
• scheme = ldap
• host = [2001:db8::7]
• path = /c=GB
• query = objectClass=one&objectClass=two
 
mailto:John.Doe@example.com
• scheme = mailto
• path = John.Doe@example.com
 
news:comp.infosystems.www.servers.unix
• scheme = news
• path = comp.infosystems.www.servers.unix
 
tel:+1-816-555-1212
• scheme = tel
• path = +1-816-555-1212
 
telnet://192.0.2.16:80/
• scheme = telnet
• host = 192.0.2.16
• port = 80
• path = /
 
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
• scheme = urn
• path = oasis:names:specification:docbook:dtd:xml:4.1.2
 
http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
• scheme = http
• host = example.com
• path = /
• query = a=1&b=2+2&c=3&c=4&d=encoded"</syntaxhighlight>
 
=={{header|C sharp|C#}}==
 
<langsyntaxhighlight lang="csharp">using System;
 
namespace RosettaUrlParse
Line 234 ⟶ 493:
}
}
</syntaxhighlight>
</lang>
 
=={{header|Crystal}}==
 
This example demonstrates use of the Crystal standard library's <code>URI</code> class.
 
<syntaxhighlight lang="crystal">require "uri"
 
examples = ["foo://example.com:8042/over/there?name=ferret#nose",
"urn:example:animal:ferret:nose",
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
"http://www.ietf.org/rfc/rfc2396.txt#header1",
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two",
"mailto:John.Doe@example.com",
"news:comp.infosystems.www.servers.unix",
"tel:+1-816-555-1212",
"telnet://192.0.2.16:80/",
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
"https://bob:password@[::1]/place?a=1&b=2%202"]
 
examples.each do |example|
puts "Parsing \"#{example}\":"
url = URI.parse example
{% for name in ["scheme", "host", "hostname", "port", "path", "userinfo",
"user", "password", "fragment", "query"] %}
unless url.{{name.id}}.nil?
puts " {{name.id}}: \"#{url.{{name.id}}}\""
end
{% end %}
unless url.query_params.empty?
puts " query_params:"
url.query_params.each do |k, v|
puts " #{k}: \"#{v}\""
end
end
puts
end</syntaxhighlight>
 
{{out}}
<pre>Parsing "foo://example.com:8042/over/there?name=ferret#nose":
scheme: "foo"
host: "example.com"
hostname: "example.com"
port: "8042"
path: "/over/there"
fragment: "nose"
query: "name=ferret"
query_params:
name: "ferret"
 
Parsing "urn:example:animal:ferret:nose":
scheme: "urn"
path: "example:animal:ferret:nose"
 
Parsing "jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true":
scheme: "jdbc"
path: "mysql://test_user:ouupppssss@localhost:3306/sakila"
query: "profileSQL=true"
query_params:
profileSQL: "true"
 
Parsing "ftp://ftp.is.co.za/rfc/rfc1808.txt":
scheme: "ftp"
host: "ftp.is.co.za"
hostname: "ftp.is.co.za"
path: "/rfc/rfc1808.txt"
 
Parsing "http://www.ietf.org/rfc/rfc2396.txt#header1":
scheme: "http"
host: "www.ietf.org"
hostname: "www.ietf.org"
path: "/rfc/rfc2396.txt"
fragment: "header1"
 
Parsing "ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two":
scheme: "ldap"
host: "[2001:db8::7]"
hostname: "2001:db8::7"
path: "/c=GB"
query: "objectClass=one&objectClass=two"
query_params:
objectClass: "one"
objectClass: "two"
 
Parsing "mailto:John.Doe@example.com":
scheme: "mailto"
path: "John.Doe@example.com"
 
Parsing "news:comp.infosystems.www.servers.unix":
scheme: "news"
path: "comp.infosystems.www.servers.unix"
 
Parsing "tel:+1-816-555-1212":
scheme: "tel"
path: "+1-816-555-1212"
 
Parsing "telnet://192.0.2.16:80/":
scheme: "telnet"
host: "192.0.2.16"
hostname: "192.0.2.16"
port: "80"
path: "/"
 
Parsing "urn:oasis:names:specification:docbook:dtd:xml:4.1.2":
scheme: "urn"
path: "oasis:names:specification:docbook:dtd:xml:4.1.2"
 
Parsing "https://bob:password@[::1]/place?a=1&b=2%202":
scheme: "https"
host: "[::1]"
hostname: "::1"
path: "/place"
userinfo: "bob:password"
user: "bob"
password: "password"
query: "a=1&b=2%202"
query_params:
a: "1"
b: "2 2"</pre>
 
=={{header|Elixir}}==
<langsyntaxhighlight lang="elixir">test_cases = [
"foo://example.com:8042/over/there?name=ferret#nose",
"urn:example:animal:ferret:nose",
Line 257 ⟶ 635:
IO.puts "\n#{str}"
IO.inspect URI.parse(str)
end)</langsyntaxhighlight>
 
{{out}}
Line 335 ⟶ 713:
<li>The System.URI class does some "Scheme-Based Normalization" (c/f rfc3986 section 6.2.3), i. e. it knows about certain
defaults for some schemes. With the test data this shows with the port numbers for http, ftp, ldap, mailto.</li></ul>
<langsyntaxhighlight lang="fsharp">open System
open System.Text.RegularExpressions
 
Line 364 ⟶ 742:
writeline " query:" (if u.Query.Length > 0 then u.Query.Substring(1) else "")
writeline " fragment:" (if u.Fragment.Length > 0 then u.Fragment.Substring(1) else "")
)</langsyntaxhighlight>
{{out}}
<pre style="height:3cm">
Line 430 ⟶ 808:
This uses Go's standard [https://golang.org/pkg/net/url/ <tt>net/url</tt>] package.
The [https://golang.org/src/net/url/url.go source code] for this package (excluding tests) is in a single file of ~720 lines.
<langsyntaxhighlight lang="go">package main
 
import (
Line 504 ⟶ 882:
fmt.Println(" Fragment:", u.Fragment)
}
}</langsyntaxhighlight>
{{out}}
<pre>
Line 580 ⟶ 958:
 
Test:
<langsyntaxhighlight lang="groovy">import java.net.URI
 
[
Line 608 ⟶ 986:
| query = ${u.query}
| fragment = ${u.fragment}""".stripMargin()
}</langsyntaxhighlight>
 
Output:
Line 704 ⟶ 1,082:
Example uses [https://hackage.haskell.org/package/network-uri <tt>network-uri</tt>] package:
 
<langsyntaxhighlight lang="haskell">module Main (main) where
 
import Data.Foldable (for_)
Line 778 ⟶ 1,156:
Nothing -> return ()
Just fragment -> putStrLn $ " fragment = " ++ fragment
putStrLn ""</langsyntaxhighlight>
{{out}}
<pre>
Line 856 ⟶ 1,234:
Implementation:
 
<langsyntaxhighlight Jlang="j">split=:1 :0
({. ; ] }.~ 1+[)~ i.&m
)
Line 902 ⟶ 1,280:
export=. ;:'scheme user creds host port path query fragment'
(#~ 0<#@>@{:"1) (,. do each) export
)</langsyntaxhighlight>
 
Task examples:
 
<langsyntaxhighlight lang="j"> taskparts 'foo://example.com:8042/over/there?name=ferret#nose'
┌────────┬─────────────┐
│scheme │foo │
Line 1,001 ⟶ 1,379:
├──────┼───────────────────────────────────────────────┤
│path │oasis:names:specification:docbook:dtd:xml:4.1.2│
└──────┴───────────────────────────────────────────────┘</langsyntaxhighlight>
 
Note that the <code>path</code> of the example <code>jdbc</code> uri is itself a uri which may be parsed:
 
<langsyntaxhighlight Jlang="j"> taskparts 'mysql://test_user:ouupppssss@localhost:3306/sakila'
┌──────┬──────────┐
│scheme│mysql │
Line 1,018 ⟶ 1,396:
├──────┼──────────┤
│path │/sakila │
└──────┴──────────┘</langsyntaxhighlight>
 
Also, examples borrowed from the <code>go</code> implementation:
 
<langsyntaxhighlight Jlang="j"> taskparts 'ssh://alice@example.com'
┌──────┬───────────┐
│scheme│ssh │
Line 1,053 ⟶ 1,431:
│ ││a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64││
│ │└─────────────────────────────────────────┘│
└──────┴───────────────────────────────────────────┘</langsyntaxhighlight>
 
Note that escape decoding is left to the consumer (as well as decoding things like '+' as a replacement for the space character and determining the absolute significance of relative paths and the details of ip address parsing and so on...). This seems like a good match to the hierarchical nature of uri parsing. See [[URL_decoding#J|URL decoding]] for an implementation of escape decoding.
Line 1,062 ⟶ 1,440:
 
=={{header|Java}}==
Java offers the ''URI'' class which will parse a URL. URNs are not supported.
In Java, you can use the <code>URI</code> class for this, so it's pretty straightforward. I just did a bit of tweaking to output.<lang Java>import java.net.URI;
<syntaxhighlight lang="java">
import java.net.URISyntaxException;
URI uri;
public class WebAddressParser{
try {
public static void main(String[] args){
uri = new parseAddressURI("foo://example.com:8042/over/there?name=ferret#nose");
} catch (URISyntaxException exception) {
parseAddress("urn:example:animal:ferret:nose");
/* invalid URI */
}
}
</syntaxhighlight>
You would then use any of the accompanying class methods to retrieve the value you're looking for.<br />
For example, to get the scheme value, you would use the following.
<syntaxhighlight lang="java">
uri.getScheme()
</syntaxhighlight>
It successfully parsed a majority of the test URLs.
<pre>
foo://example.com:8042/over/there?name=ferret#nose
scheme: foo
userinfo:
host: example.com
port: 8042
authority: example.com:8042
path: /over/there
query: name=ferret
fragment: nose
</pre>
To parse the 'jdbc:' URL you'll need to remove the prefix.
<pre>
mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
scheme: mysql
userinfo: test_user:ouupppssss
host: localhost
port: 3306
authority: test_user:ouupppssss@localhost:3306
path: /sakila
query: profileSQL=true
fragment:
</pre>
The others work as expected, except for 'mailto', 'news', and 'tel'.<br />
Although, these are not too complicated to parse. For 'mailto', I used a class with two records.<br />
RFC 6068 defines a 'mailto' scheme. https://datatracker.ietf.org/doc/html/rfc6068.
<syntaxhighlight lang="java">
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
 
public class MailTo {
static void parseAddress(String a){
private final To to;
System.out.println("Parsing " + a);
private List<Field> fields;
try{
 
public MailTo(String string) {
// this line does the work
if URI u(string == new URI(anull);
throw new NullPointerException();
 
if (string.isBlank() || !string.toLowerCase().startsWith("mailto:"))
System.out.println("\tscheme = " + u.getScheme());
System.out.printlnthrow new IllegalArgumentException("\tdomainRequires ='mailto' scheme" + u.getHost());
string = string.substring(string.indexOf(':') + 1);
System.out.println("\tport = " + (-1==u.getPort()?"default":u.getPort()));
/* we can use the 'URLDecoder' class to decode any entities */
System.out.println("\tpath = " + (null==u.getPath()?u.getSchemeSpecificPart():u.getPath()));
string = SystemURLDecoder.out.printlndecode("\tquerystring, = " + uStandardCharsets.getQuery()UTF_8);
/* the address and fields are separated by a '?' */
System.out.println("\tfragment = " + u.getFragment());
int indexOf = string.indexOf('?');
}
catchString[] (URISyntaxException x){address;
if System.err.println("Oops: "indexOf +== x-1);
address = string.split("@");
else {
address = string.substring(0, indexOf).split("@");
string = string.substring(indexOf + 1);
/* each field is separated by a '&' */
String[] fields = string.split("&");
String[] field;
this.fields = new ArrayList<>(fields.length);
for (String value : fields) {
field = value.split("=");
this.fields.add(new Field(field[0], field[1]));
}
}
to = new To(address[0], address[1]);
}
 
record To(String user, String host) { }
record Field(String name, String value) { }
}
</syntaxhighlight>
</lang>I'm only showing two examples, but the others work too, honest.
I ran a majority of the examples from RFC 6068 and got the expected results
{{Out}}
<pre>
<pre>Parsing foo://example.com:8042/over/there?name=ferret#nose
mailto:infobot@example.com?subject=current-issue
scheme = foo
user infobot
domain = example.com
host example.com
port = 8042
name subject
path = /over/there
value current-issue
query = name=ferret
 
fragment = nose
mailto:list@example.org?In-Reply-To=%3C3469A91.D10AF4C@example.com%3E
Parsing urn:example:animal:ferret:nose
user list
scheme = urn
host example.org
domain = null
name In-Reply-To
port = default
value <3469A91.D10AF4C@example.com>
path = example:animal:ferret:nose
</pre>
query = null
Both 'tel' and 'news' are similar, and actually simpler.<br />
fragment = null</pre>
RFC 3966 outlines the 'tel' syntaxs. https://datatracker.ietf.org/doc/html/rfc3966.<br />
And RFC 5538 outlines the 'news' syntax. https://www.rfc-editor.org/rfc/rfc5538.html.
 
=={{header|JavaScript}}==
Line 1,112 ⟶ 1,547:
Here is an example, tested against the JavaScript engines of current versions of Chrome and Safari, of taking this 'Gordian knot' approach to the task:
 
<langsyntaxhighlight JavaScriptlang="javascript">(function (lstURL) {
 
var e = document.createElement('a'),
Line 1,157 ⟶ 1,592:
"https://bob:pass@example.com/place",
"http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"
]);</langsyntaxhighlight>
 
Results of applying this approach in the JavaScript of Safari 8
<syntaxhighlight lang="json">[
<lang JSON>[
{
"hash": "#nose",
Line 1,301 ⟶ 1,736:
"search": "?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"
}
]</langsyntaxhighlight>
 
=={{header|jq}}==
{{works with|jq}}
'''Works with gojq, the Go implementation of jq.'''
 
Since jq does not provide a URL parser, and since the RFC 3986
specification is in fact quite complex, this entry will for the most
part focus on the task of parsing a correctly formed URL into
the five main components specified in Appendix B of the RFC:
 
# scheme
# authority
# path
# query
# fragment
 
However, since the Rosetta Code task description above evinces particular interest in
"authority" segments of the form:
 
* [username:password@]domain[:port]
 
this entry will adopt a hierarchical approach to parsing so that the
full URL parser defined here will when possible also break down the "authority"
segment into the four components `username`, `password`, `domain` and `port`.
 
One advantage of this hierarchical approach is that it facilitates
further refinements and extensions, including error-handling
in the event of invalid components.
 
Note that the regular expression used to define the jq filter `URL` here is
equivalent to the one specified in Appendix B of the RFC and can
therefore be taken as authoritative.
 
Note also that the following does not tackle the task of decoding special characters (e.g. "+" in the query string).
 
<syntaxhighlight lang=jq>
# See Appendix B of RFC 3986
def URL:
capture("^((?<scheme>[^:/?#]+):)?(//(?<authority>[^/?#]*))?(?<path>[^?#]*)(\\?(?<query>[^#]*))?(#(?<fragment>.*))?");
 
# The authority could be of the form: [username:password@]domain[:port]
def authority:
capture( "^((?<username>[^:@/]*):(?<password>[^@]*)@)?(?<domain>[^:?]*)(:(?<port>[0-9]*))?$" );
 
# The following filter first parses a valid URL into the five basic
# components, producing a JSON object with five keys; if the "authority"
# field can be futher parsed by `authority`, it is replaced by the
# corresponding JSON object.
def uri:
URL
| if .authority
then (.authority|authority) as $authority
| if $authority then .authority |= $authority
else .
end
else .
end;
</syntaxhighlight>
 
'''Examples'''
<syntaxhighlight lang=jq>
def tests:
"foo://example.com:8042/over/there?name=ferret&color=grey#nose",
"urn:example:animal:ferret:nose",
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
"http://www.ietf.org/rfc/rfc2396.txt#header1",
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two",
"mailto:John.Doe@example.com",
"news:comp.infosystems.www.servers.unix",
"tel:+1-816-555-1212",
"telnet://192.0.2.16:80/",
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2"
;
 
# For brevity, drop the `null`s:
tests
| [., (uri | (.. | select(.==null)) |= empty) ]
</syntaxhighlight>
{{output}}
<pre>
[
"foo://example.com:8042/over/there?name=ferret&color=grey#nose",
{
"scheme": "foo",
"authority": {
"domain": "example.com",
"port": "8042"
},
"path": "/over/there",
"query": "name=ferret&color=grey",
"fragment": "nose"
}
]
[
"urn:example:animal:ferret:nose",
{
"scheme": "urn",
"path": "example:animal:ferret:nose"
}
]
[
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
{
"scheme": "jdbc",
"path": "mysql://test_user:ouupppssss@localhost:3306/sakila",
"query": "profileSQL=true"
}
]
[
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
{
"scheme": "ftp",
"authority": {
"domain": "ftp.is.co.za"
},
"path": "/rfc/rfc1808.txt"
}
]
[
"http://www.ietf.org/rfc/rfc2396.txt#header1",
{
"scheme": "http",
"authority": {
"domain": "www.ietf.org"
},
"path": "/rfc/rfc2396.txt",
"fragment": "header1"
}
]
[
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two"
]
[
"mailto:John.Doe@example.com",
{
"scheme": "mailto",
"path": "John.Doe@example.com"
}
]
[
"news:comp.infosystems.www.servers.unix",
{
"scheme": "news",
"path": "comp.infosystems.www.servers.unix"
}
]
[
"tel:+1-816-555-1212",
{
"scheme": "tel",
"path": "+1-816-555-1212"
}
]
[
"telnet://192.0.2.16:80/",
{
"scheme": "telnet",
"authority": {
"domain": "192.0.2.16",
"port": "80"
},
"path": "/"
}
]
[
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
{
"scheme": "urn",
"path": "oasis:names:specification:docbook:dtd:xml:4.1.2"
}
]
</pre>
 
=={{header|Julia}}==
This solution uses Julia's [https://github.com/JuliaWeb/URIParser.jl URIParser] package. The <code>detailview</code> function shows all of the non-empty components of the <code>URI</code> object created by this parser. No attempt is made to further parse more complex components, e.g. query or userinfo. Error detection is limited to indicating whether a string is parsable as a URI and providing a hint as to whether the <code>URI</code> is valid (according to this package's <code>isvalid</code> function).
<syntaxhighlight lang="julia">using Printf, URIParser
<lang Julia>
 
using URIParser
const FIELDS = names(URI)
 
Line 1,359 ⟶ 1,967:
println(detailview(uri))
end
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,485 ⟶ 2,093:
=={{header|Kotlin}}==
Although the java.net.URL class can parse urls just fine, unfortunately (as far as this task is concerned) the constructor throws an exception if it does not recognize the scheme (or 'protocol' as it calls it). To deal with unrecognized protocols such as 'foo', we therefore need to replace them with a valid protocol such as 'http' to trick the URL class into parsing them properly:
<langsyntaxhighlight lang="scala">// version 1.1.2
 
import java.net.URL
Line 1,534 ⟶ 2,142:
)
for (url in urls) parseUrl(url)
}</langsyntaxhighlight>
 
{{out}}
Line 1,616 ⟶ 2,224:
{{libheader|LuaSocket}}
 
<langsyntaxhighlight lang="lua">local url = require('socket.url')
 
local tests = {
Line 1,643 ⟶ 2,251:
io.write('\n')
end
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 1,707 ⟶ 2,315:
path: oasis:names:specification:docbook:dtd:xml:4.1.2
</pre>
 
=={{header|M2000 Interpreter}}==
===Using M2000 script to parse URL===
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module checkit {
any=lambda (z$)->{=lambda z$ (a$)->instr(z$,a$)>0}
Line 1,876 ⟶ 2,485:
}
Checkit
</syntaxhighlight>
</lang>
{{out}}
<pre style="height:30ex;overflow:scroll">
Line 1,920 ⟶ 2,529:
 
===Using an internal function (variation of String$())===
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
module Checkit {
Stack New {
Line 1,962 ⟶ 2,571:
}
Checkit
</syntaxhighlight>
</lang>
{{out}}
<pre style="height:30ex;overflow:scroll">
Line 2,123 ⟶ 2,732:
</pre >
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">URLParse["foo://example.com:8042/over/there?name=ferret#nose"]</langsyntaxhighlight>
{{out}}
<pre><|"Scheme" -> "foo", "User" -> None, "Domain" -> "example.com",
Line 2,131 ⟶ 2,740:
 
=={{header|Nim}}==
The <code>uri</code> module provides a <code>parseUri</code> proc...
 
<syntaxhighlight lang ="nim">import std/[uri, strformat, strutils]
 
proc printUri(url: string) =
Line 2,157 ⟶ 2,766:
echo &"\t Opaque: {res.opaque}"
 
let urls = @["foo://example.com:8042/over/there?name=ferret#nose",
"urn:example:animal:ferret:nose",
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
Line 2,173 ⟶ 2,782:
 
for url in urls:
printUri(url)</langsyntaxhighlight>
{{out}}
<pre>foo://example.com:8042/over/there?name=ferret#nose
Line 2,245 ⟶ 2,854:
=={{header|Objeck}}==
 
<langsyntaxhighlight lang="objeck">use Web.HTTP;
 
class Test {
Line 2,270 ⟶ 2,879:
};
}
}</langsyntaxhighlight>
 
{{out}}
Line 2,336 ⟶ 2,945:
=={{header|Perl}}==
You can use the URI module from CPAN to parse URIs. Note that the output is a bit different: for example, you don't get the host from the <code>foo://</code> scheme, as host is only valid for schemes that define it.
<langsyntaxhighlight lang="perl">#!/usr/bin/perl
use warnings;
use strict;
Line 2,363 ⟶ 2,972:
}
 
}</langsyntaxhighlight>
{{out}}
<pre>foo://example.com:8042/over/there?name=ferret#nose
Line 2,417 ⟶ 3,026:
scheme urn
path oasis:names:specification:docbook:dtd:xml:4.1.2</pre>
 
=={{header|Perl 6}}==
{{works with|rakudo|2015-11-02}}
Uses the URI library which implements a Perl 6 grammar based on the RFC 3986 BNF grammar.
<lang perl6>use URI;
 
my @test-uris = <
foo://example.com:8042/over/there?name=ferret#nose
urn:example:animal:ferret:nose
jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt#header1
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
>;
 
my $u = URI.new;
 
for @test-uris -> $uri {
say "URI:\t", $uri;
$u.parse($uri);
for <scheme host port path query frag> -> $t {
my $token = try {$u."$t"()} || '';
say "$t:\t", $token if $token;
}
say '';
}</lang>
{{out}}
<pre>URI: foo://example.com:8042/over/there?name=ferret#nose
scheme: foo
host: example.com
port: 8042
path: /over/there
query: name=ferret
frag: nose
 
URI: urn:example:animal:ferret:nose
scheme: urn
path: example:animal:ferret:nose
 
URI: jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
scheme: jdbc
path: mysql://test_user:ouupppssss@localhost:3306/sakila
query: profileSQL=true
 
URI: ftp://ftp.is.co.za/rfc/rfc1808.txt
scheme: ftp
host: ftp.is.co.za
port: 21
path: /rfc/rfc1808.txt
 
URI: http://www.ietf.org/rfc/rfc2396.txt#header1
scheme: http
host: www.ietf.org
port: 80
path: /rfc/rfc2396.txt
frag: header1
 
URI: ldap://[2001:db8::7]/c=GB?objectClass?one
scheme: ldap
host: [2001:db8::7]
port: 389
path: /c=GB
query: objectClass?one
 
URI: mailto:John.Doe@example.com
scheme: mailto
path: John.Doe@example.com
 
URI: news:comp.infosystems.www.servers.unix
scheme: news
port: 119
path: comp.infosystems.www.servers.unix
 
URI: tel:+1-816-555-1212
scheme: tel
path: +1-816-555-1212
 
URI: telnet://192.0.2.16:80/
scheme: telnet
host: 192.0.2.16
port: 80
path: /
 
URI: urn:oasis:names:specification:docbook:dtd:xml:4.1.2
scheme: urn
path: oasis:names:specification:docbook:dtd:xml:4.1.2
</pre>
 
=={{header|Phix}}==
There isare asome fairly rudimentary and undocumentedlightly routinedocumented routines in pfilebuiltins/url.e, parse_url().
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>include builtins\pfile.e
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
 
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">/</span><span style="color: #000000;">url</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
sequence descs = repeat("",8)
descs[URL_PROTOCOL] = "scheme"
<span style="color: #008080;">procedure</span> <span style="color: #000000;">show_url_details</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">uri</span><span style="color: #0000FF;">)</span>
descs[URL_HOSTNAME] = "domain"
<span style="color: #0000FF;">?</span><span style="color: #000000;">uri</span>
descs[URL_PORT] = "port"
<span style="color: #004080;">sequence</span> <span style="color: #000000;">r</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">parse_url</span><span style="color: #0000FF;">(</span><span style="color: #000000;">uri</span><span style="color: #0000FF;">)</span>
descs[URL_PATH] = "path"
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">r</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
descs[URL_USER] = "user"
<span style="color: #008080;">if</span> <span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
descs[URL_PASSWORD] = "password"
<span style="color: #004080;">string</span> <span style="color: #000000;">desc</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">url_element_desc</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">)</span>
descs[URL_QUERY_STRING] = "query"
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s : %v\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">desc</span><span style="color: #0000FF;">,</span><span style="color: #000000;">r</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]})</span>
descs[URL_FRAGMENT] = "fragment"
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
procedure show_url_details(string uri)
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">)</span>
sequence r = parse_url(uri)
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
?uri
for i=1 to length(descs) do
<span style="color: #008080;">constant</span> <span style="color: #000000;">tests</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span>
if r[i]!=0 then
<span style="color: #008000;">"foo://example.com:8042/over/there?name=ferret#nose"</span><span style="color: #0000FF;">,</span>
printf(1,"%s : %s\n",{descs[i],sprint(r[i])})
<span style="color: #008000;">"urn:example:animal:ferret:nose"</span><span style="color: #0000FF;">,</span>
end if
<span style="color: #008000;">"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true"</span><span style="color: #0000FF;">,</span>
end for
<span style="color: #008000;">"ftp://ftp.is.co.za/rfc/rfc1808.txt"</span><span style="color: #0000FF;">,</span>
puts(1,"\n")
<span style="color: #008000;">"http://www.ietf.org/rfc/rfc2396.txt#header1"</span><span style="color: #0000FF;">,</span>
end procedure
<span style="color: #008000;">"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two"</span><span style="color: #0000FF;">,</span>
 
<span style="color: #008000;">"mailto:John.Doe@example.com"</span><span style="color: #0000FF;">,</span>
constant tests = {
<span style="color: #008000;">"news:comp.infosystems.www.servers.unix"</span><span style="color: #0000FF;">,</span>
"foo://example.com:8042/over/there?name=ferret#nose",
<span style="color: #008000;">"tel:+1-816-555-1212"</span><span style="color: #0000FF;">,</span>
"urn:example:animal:ferret:nose",
<span style="color: #008000;">"telnet://192.0.2.16:80/"</span><span style="color: #0000FF;">,</span>
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
<span style="color: #008000;">"urn:oasis:names:specification:docbook:dtd:xml:4.1.2"</span><span style="color: #0000FF;">,</span>
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
<span style="color: #008000;">"ssh://alice@example.com"</span><span style="color: #0000FF;">,</span>
"http://www.ietf.org/rfc/rfc2396.txt#header1",
<span style="color: #008000;">"https://bob:pass@example.com/place"</span><span style="color: #0000FF;">,</span>
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two",
<span style="color: #008000;">"http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"</span>
"mailto:John.Doe@example.com",
<span style="color: #0000FF;">}</span>
"news:comp.infosystems.www.servers.unix",
"tel:+1-816-555-1212",
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
"telnet://192.0.2.16:80/",
<span style="color: #000000;">show_url_details</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tests</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">])</span>
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
"ssh://alice@example.com",
<!--</syntaxhighlight>-->
"https://bob:pass@example.com/place",
"http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"
}
 
for i=1 to length(tests) do
show_url_details(tests[i])
end for</lang>
{{Out}}
<pre>
Line 2,631 ⟶ 3,142:
query : "a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64"
</pre>
 
=={{header|PHP}}==
 
Using the parse_url function (Parse a URL and return its components)
 
<syntaxhighlight lang="php"><?php
 
$urls = array(
'foo://example.com:8042/over/there?name=ferret#nose',
'urn:example:animal:ferret:nose',
'jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true',
'ftp://ftp.is.co.za/rfc/rfc1808.txt',
'http://www.ietf.org/rfc/rfc2396.txt#header1',
'ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two',
'mailto:John.Doe@example.com',
'news:comp.infosystems.www.servers.unix',
'tel:+1-816-555-1212',
'telnet://192.0.2.16:80/',
'urn:oasis:names:specification:docbook:dtd:xml:4.1.2',
);
 
foreach ($urls AS $url) {
$p = parse_url($url);
echo $url, PHP_EOL;
print_r($p);
echo PHP_EOL;
}</syntaxhighlight>
 
{{out}}
<pre style="height:256px">foo://example.com:8042/over/there?name=ferret#nose
Array
(
[scheme] => foo
[host] => example.com
[port] => 8042
[path] => /over/there
[query] => name=ferret
[fragment] => nose
)
 
urn:example:animal:ferret:nose
Array
(
[scheme] => urn
[path] => example:animal:ferret:nose
)
 
jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
Array
(
[scheme] => jdbc
[path] => mysql://test_user:ouupppssss@localhost:3306/sakila
[query] => profileSQL=true
)
 
ftp://ftp.is.co.za/rfc/rfc1808.txt
Array
(
[scheme] => ftp
[host] => ftp.is.co.za
[path] => /rfc/rfc1808.txt
)
 
http://www.ietf.org/rfc/rfc2396.txt#header1
Array
(
[scheme] => http
[host] => www.ietf.org
[path] => /rfc/rfc2396.txt
[fragment] => header1
)
 
ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
Array
(
[scheme] => ldap
[host] => [2001:db8::7]
[path] => /c=GB
[query] => objectClass=one&objectClass=two
)
 
mailto:John.Doe@example.com
Array
(
[scheme] => mailto
[path] => John.Doe@example.com
)
 
news:comp.infosystems.www.servers.unix
Array
(
[scheme] => news
[path] => comp.infosystems.www.servers.unix
)
 
tel:+1-816-555-1212
Array
(
[scheme] => tel
[path] => +1-816-555-1212
)
 
telnet://192.0.2.16:80/
Array
(
[scheme] => telnet
[host] => 192.0.2.16
[port] => 80
[path] => /
)
 
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
Array
(
[scheme] => urn
[path] => oasis:names:specification:docbook:dtd:xml:4.1.2
)</pre>
 
=={{header|PowerShell}}==
I was confused about the '''Path''' parameter. PowerShell returns '''LocalPath''', '''AbsolutePath''' and '''AbsoluteUri'''; I defaulted to '''LocalPath''', but all properties are returned in the <code>$parsedUrls</code> variable.
<syntaxhighlight lang="powershell">
<lang PowerShell>
function Get-ParsedUrl
{
Line 2,678 ⟶ 3,306:
}
}
</syntaxhighlight>
</lang>
<syntaxhighlight lang="powershell">
<lang PowerShell>
[string[]]$urls = @'
foo://example.com:8042/over/there?name=ferret#nose
Line 2,697 ⟶ 3,325:
 
$parsedUrls | Select-Object -Property Scheme, Port, Domain, Path, Query, Fragment | Format-Table
</syntaxhighlight>
</lang>
{{Out}}
<pre>
Line 2,717 ⟶ 3,345:
=={{header|Python}}==
Links to Python Documentation: v2: [https://docs.python.org/2/library/urlparse.html#module-urlparse], v3: [https://docs.python.org/3.4/library/urllib.parse.html]
<langsyntaxhighlight Pythonlang="python">import urllib.parse as up # urlparse for Python v2
 
url = up.urlparse('http://user:pass@example.com:8081/path/file.html;params?query1=1#fragment')
Line 2,731 ⟶ 3,359:
print('url.username = ', url.username)
print('url.password = ', url.password)
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,745 ⟶ 3,373:
url.password = pass
</pre>
 
=={{header|R}}==
urltools::url_parse() do all the actually work. The rest is just for nice output.
<langsyntaxhighlight lang="rsplus">
library(urltools)
 
Line 2,775 ⟶ 3,404:
cat("\n")
}
</syntaxhighlight>
</lang>
{{out}}
<pre>
Line 2,847 ⟶ 3,476:
parameter : a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
</pre>
 
=={{header|Racket}}==
Links: [http://docs.racket-lang.org/net/url.html?q=url#%28def._%28%28lib._net%2Furl-structs..rkt%29._url%29%29 <code>url</code> structure in Racket documentation].
 
<langsyntaxhighlight lang="racket">#lang racket/base
(require racket/match net/url)
(define (debug-url-string U)
Line 2,885 ⟶ 3,515:
"tel:+1-816-555-1212"
"telnet://192.0.2.16:80/"
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2"))</langsyntaxhighlight>
 
{{out}}
Line 2,966 ⟶ 3,596:
path bits: ("oasis:names:specification:docbook:dtd:xml:4.1.2")</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|rakudo|2015-11-02}}
Uses the URI library which implements a Raku grammar based on the RFC 3986 BNF grammar.
<syntaxhighlight lang="raku" line>use URI;
use URI::Escape;
 
my @test-uris = <
foo://example.com:8042/over/there?name=ferret#nose
urn:example:animal:ferret:nose
jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt#header1
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:John.Doe@example.com
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
ssh://alice@example.com
https://bob:pass@example.com/place
http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
>;
 
my $u = URI.new;
 
for @test-uris -> $uri {
say "URI:\t", $uri;
$u.parse($uri);
for <scheme host port path query frag> -> $t {
my $token = try {$u."$t"()} || '';
say "$t:\t", uri-unescape $token.Str if $token;
}
say '';
}</syntaxhighlight>
{{out}}
<pre>URI: foo://example.com:8042/over/there?name=ferret#nose
scheme: foo
host: example.com
port: 8042
path: /over/there
query: name=ferret
frag: nose
 
URI: urn:example:animal:ferret:nose
scheme: urn
path: example:animal:ferret:nose
 
URI: jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
scheme: jdbc
path: mysql://test_user:ouupppssss@localhost:3306/sakila
query: profileSQL=true
 
URI: ftp://ftp.is.co.za/rfc/rfc1808.txt
scheme: ftp
host: ftp.is.co.za
port: 21
path: /rfc/rfc1808.txt
 
URI: http://www.ietf.org/rfc/rfc2396.txt#header1
scheme: http
host: www.ietf.org
port: 80
path: /rfc/rfc2396.txt
frag: header1
 
URI: ldap://[2001:db8::7]/c=GB?objectClass?one
scheme: ldap
host: [2001:db8::7]
port: 389
path: /c=GB
query: objectClass?one
 
URI: mailto:John.Doe@example.com
scheme: mailto
path: John.Doe@example.com
 
URI: news:comp.infosystems.www.servers.unix
scheme: news
port: 119
path: comp.infosystems.www.servers.unix
 
URI: tel:+1-816-555-1212
scheme: tel
path: 1-816-555-1212
 
URI: telnet://192.0.2.16:80/
scheme: telnet
host: 192.0.2.16
port: 80
path: /
 
URI: urn:oasis:names:specification:docbook:dtd:xml:4.1.2
scheme: urn
path: oasis:names:specification:docbook:dtd:xml:4.1.2
 
URI: ssh://alice@example.com
scheme: ssh
host: example.com
port: 22
path:
 
URI: https://bob:pass@example.com/place
scheme: https
host: example.com
port: 443
path: /place
 
URI: http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
scheme: http
host: example.com
port: 80
path: /
query: a=1&b=2 2&c=3&c=4&d=encoded</pre>
 
=={{header|Ruby}}==
Line 2,971 ⟶ 3,715:
 
As you can see in the output below, the URI library doesn't parse all of these as recommended.
<langsyntaxhighlight Rubylang="ruby">require 'uri'
 
test_cases = [
Line 2,998 ⟶ 3,742:
puts " #{attr.rjust(8)} = #{uri.send(attr)}" if uri.send(attr)
end
end</langsyntaxhighlight>
{{out}}
<pre>foo://example.com:8042/over/there?name=ferret#nose
Line 3,059 ⟶ 3,803:
path = /
query = a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">use url::Url;
 
fn print_fields(url: Url) -> () {
println!("scheme: {}", url.scheme());
println!("username: {}", url.username());
 
if let Some(password) = url.password() {
println!("password: {}", password);
}
 
if let Some(domain) = url.domain() {
println!("domain: {}", domain);
}
 
if let Some(port) = url.port() {
println!("port: {}", port);
}
println!("path: {}", url.path());
 
if let Some(query) = url.query() {
println!("query: {}", query);
}
 
if let Some(fragment) = url.fragment() {
println!("fragment: {}", fragment);
}
}
fn main() {
let urls = vec![
"foo://example.com:8042/over/there?name=ferret#nose",
"urn:example:animal:ferret:nose",
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
"http://www.ietf.org/rfc/rfc2396.txt#header1",
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two",
"mailto:John.Doe@example.com",
"news:comp.infosystems.www.servers.unix",
"tel:+1-816-555-1212",
"telnet://192.0.2.16:80/",
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
"ssh://alice@example.com",
"https://bob:pass@example.com/place",
"http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64",
];
 
for url in urls {
println!("Parsing {}", url);
match Url::parse(url) {
Ok(valid_url) => {
print_fields(valid_url);
println!();
}
Err(e) => println!("Error Parsing url - {:?}", e),
}
}
}
</syntaxhighlight>
Output:
<pre>
Parsing foo://example.com:8042/over/there?name=ferret#nose
scheme: foo
username:
domain: example.com
port: 8042
path: /over/there
query: name=ferret
fragment: nose
 
Parsing urn:example:animal:ferret:nose
scheme: urn
username:
path: example:animal:ferret:nose
 
Parsing jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
scheme: jdbc
username:
path: mysql://test_user:ouupppssss@localhost:3306/sakila
query: profileSQL=true
 
Parsing ftp://ftp.is.co.za/rfc/rfc1808.txt
scheme: ftp
username:
domain: ftp.is.co.za
path: /rfc/rfc1808.txt
 
Parsing http://www.ietf.org/rfc/rfc2396.txt#header1
scheme: http
username:
domain: www.ietf.org
path: /rfc/rfc2396.txt
fragment: header1
 
Parsing ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
scheme: ldap
username:
path: /c=GB
query: objectClass=one&objectClass=two
 
Parsing mailto:John.Doe@example.com
scheme: mailto
username:
path: John.Doe@example.com
 
Parsing news:comp.infosystems.www.servers.unix
scheme: news
username:
path: comp.infosystems.www.servers.unix
 
Parsing tel:+1-816-555-1212
scheme: tel
username:
path: +1-816-555-1212
 
Parsing telnet://192.0.2.16:80/
scheme: telnet
username:
domain: 192.0.2.16
port: 80
path: /
 
Parsing urn:oasis:names:specification:docbook:dtd:xml:4.1.2
scheme: urn
username:
path: oasis:names:specification:docbook:dtd:xml:4.1.2
 
Parsing ssh://alice@example.com
scheme: ssh
username: alice
domain: example.com
path:
 
Parsing https://bob:pass@example.com/place
scheme: https
username: bob
password: pass
domain: example.com
path: /place
 
Parsing http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
scheme: http
username:
domain: example.com
path: /
query: a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
</pre>
 
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">import java.net.URI
 
object WebAddressParser extends App {
Line 3,094 ⟶ 3,985:
} catch { case ex: Throwable => println('\u2718') }
}
}</langsyntaxhighlight>
{{Out}}See it in running in your browser by [https://scastie.scala-lang.org/GZdtfkhfRsa9QPKZQ7W4XQ Scastie (JVM)].
 
=={{header|Tcl}}==
 
Line 3,108 ⟶ 4,000:
The <tt>uri</tt> package doesn't presently handle IPv6 syntx as used in the example: a bug and patch will be submitted presently ..
 
<langsyntaxhighlight Tcllang="tcl">package require uri
package require uri::urn
 
Line 3,147 ⟶ 4,039:
puts \n$uri
pdict [parse_uri $uri]
}</langsyntaxhighlight>
 
{{out}}
Line 3,208 ⟶ 4,100:
 
=={{header|VBScript}}==
<syntaxhighlight lang="vb">
<lang vb>
Function parse_url(url)
parse_url = "URL: " & url
Line 3,305 ⟶ 4,197:
WScript.StdOut.WriteLine "-------------------------------"
WScript.StdOut.WriteLine parse_url("this code is messy, long, and needs a makeover!!!")
</syntaxhighlight>
</lang>
 
{{Out}}
Line 3,367 ⟶ 4,259:
URL: this code is messy, long, and needs a makeover!!!
Invalid!!!
</pre>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">import net.urllib
 
const urls = ['jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true',
'ftp://ftp.is.co.za/rfc/rfc1808.txt',
'http://www.ietf.org/rfc/rfc2396.txt#header1',
'ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two',
'mailto:John.Doe@example.com',
'news:comp.infosystems.www.servers.unix',
'tel:+1-816-555-1212',
'telnet://192.0.2.16:80/',
'urn:oasis:names:specification:docbook:dtd:xml:4.1.2',
'foo://example.com:8042/over/there?name=ferret#nose'
]
 
fn main() {
for url in urls {
u := urllib.parse(url)?
println(u)
print_url(u)
}
}
 
fn print_url(u urllib.URL) {
println(" Scheme: $u.scheme")
if u.opaque != "" {
println(" Opaque: $u.opaque")
}
if u.str() == '' {
println(" Username: $u.user.username")
if u.user.password != '' {
println(" Password: $u.user.password")
}
}
if u.host != "" {
if u.port() != '' {
println(" Host: ${u.hostname()}")
println(" Port: ${u.port()}")
} else {
println(" Host: $u.host")
}
}
if u.path != "" {
println(" Path: $u.path")
}
if u.raw_query != "" {
println(" RawQuery: $u.raw_query")
m := u.query().data
for q in m {
println(" Key: $q.key Values: $q.value")
}
}
if u.fragment != "" {
println(" Fragment: $u.fragment")
}
}</syntaxhighlight>
{{out}}
<pre>jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
Scheme: jdbc
Opaque: mysql://test_user:ouupppssss@localhost:3306/sakila
RawQuery: profileSQL=true
Key: profileSQL Values: true
ftp://ftp.is.co.za/rfc/rfc1808.txt
Scheme: ftp
Host: ftp.is.co.za
Path: /rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc2396.txt#header1
Scheme: http
Host: www.ietf.org
Path: /rfc/rfc2396.txt
Fragment: header1
ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
Scheme: ldap
Host: [2001:db8::7]
Path: /c=GB
RawQuery: objectClass=one&objectClass=two
Key: objectClass Values: one
Key: objectClass Values: two
mailto:John.Doe@example.com
Scheme: mailto
Opaque: John.Doe@example.com
news:comp.infosystems.www.servers.unix
Scheme: news
Opaque: comp.infosystems.www.servers.unix
tel:+1-816-555-1212
Scheme: tel
Opaque: +1-816-555-1212
telnet://192.0.2.16:80/
Scheme: telnet
Host: 192.0.2.16
Port: 80
Path: /
urn:oasis:names:specification:docbook:dtd:xml:4.1.2
Scheme: urn
Opaque: oasis:names:specification:docbook:dtd:xml:4.1.2
foo://example.com:8042/over/there?name=ferret#nose
Scheme: foo
Host: example.com
Port: 8042
Path: /over/there
RawQuery: name=ferret
Key: name Values: ferret
Fragment: nose
</pre>
 
=={{header|Wren}}==
{{trans|VBScript}}
... though modified quite a bit.
<syntaxhighlight lang="wren">var urlParse = Fn.new { |url|
var parseUrl = "URL = " + url
var index
if ((index = url.indexOf("//")) && index >= 0 && url[0...index].count { |c| c == ":" } == 1) {
// parse the scheme
var scheme = url.split("//")
parseUrl = parseUrl + "\n" + "Scheme = " + scheme[0][0..-2]
// parse the domain
var domain = scheme[1].split("/")
// check if the domain includes a username, password and port
if (domain[0].contains("@")) {
var cred = domain[0].split("@")
var split = [cred[0], ""]
if (cred[0].contains(".")) {
split = cred[0].split(".")
} else if (cred[0].contains(":")) {
split = cred[0].split(":")
}
var username = split[0]
var password = split[1]
parseUrl = parseUrl + "\n" + "Username = " + username
if (password != "") parseUrl = parseUrl + "\n" + "Password = " + password
// check if the domain has a port
if (cred[1].contains(":")) {
split = cred[1].split(":")
var host = split[0]
var port = ":" + split[1]
parseUrl = parseUrl + "\n" + "Domain = " + host + "\n" + "Port = " + port
} else {
parseUrl = parseUrl + "\n" + "Domain = " + cred[1]
}
} else if (domain[0].contains(":") && !domain[0].contains("[") && !domain[0].contains("]")) {
var split = domain[0].split(":")
var host = split[0]
var port = ":" + split[1]
parseUrl = parseUrl + "\n" + "Domain = " + host + "\n" + "Port = " + port
} else if (domain[0].contains("[") && domain[0].contains("]:")) {
var split = domain[0].split("]")
var host = split[0] + "]"
var port = ":" + split[1][1..-1]
parseUrl = parseUrl + "\n" + "Domain = " + host + "\n" + "Port = " + port
} else {
parseUrl = parseUrl + "\n" + "Domain = " + domain[0]
}
// parse the path if it exists
if (domain.count > 1) {
var path = "/"
for (i in 1...domain.count) {
if (i < domain.count - 1) {
path = path + domain[i] + "/"
} else if (domain[i].contains("?")) {
var split = domain[i].split("?")
path = path + split[0]
if (domain[i].contains("#")) {
var split2 = split[1].split("#")
var query = split2[0]
var fragment = split2[1]
path = path + "\n" + "Query = " + query + "\n" + "Fragment = " + fragment
} else {
var query = split[1]
path = path + "\n" + "Query = " + query
}
} else if (domain[i].contains("#")) {
var split = domain[i].split("#")
var fragment = split[1]
path = path + split[0] + "\n" + "Fragment = " + fragment
} else {
path = path + domain[i]
}
}
parseUrl = parseUrl + "\n" + "Path = " + path
}
} else if (url.contains(":")) {
var index = url.indexOf(":")
var scheme = url[0...index]
parseUrl = parseUrl + "\n" + "Scheme = " + scheme + "\n"
var path = url[index+1..-1]
if (!path.contains("?")) {
parseUrl = parseUrl + "Path = " + path
} else {
var split = path.split("?")
var query = split[1]
parseUrl = parseUrl + "Path = " + split[0] + "\n"
if (!query.contains("#")) {
parseUrl = parseUrl + "Query = " + query
} else {
split = query.split("#")
var fragment = split[1]
parseUrl = parseUrl + "Query = " + split[0] + "Fragment = " + fragment
}
}
} else {
parseUrl = parseUrl + "\n" + "Invalid!!!"
}
System.print(parseUrl)
System.print()
}
 
var urls = [
"foo://example.com:8042/over/there?name=ferret#nose",
"urn:example:animal:ferret:nose",
"jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true",
"ftp://ftp.is.co.za/rfc/rfc1808.txt",
"http://www.ietf.org/rfc/rfc2396.txt#header1",
"ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two",
"mailto:John.Doe@example.com",
"news:comp.infosystems.www.servers.unix",
"tel:+1-816-555-1212",
"telnet://192.0.2.16:80/",
"urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
"ssh://alice@example.com",
"https://bob:pass@example.com/place",
"http://example.com/?a=1&b=2+2&c=3&c=4&d=\%65\%6e\%63\%6F\%64\%65\%64"
]
for (url in urls) urlParse.call(url)</syntaxhighlight>
 
{{out}}
<pre>
URL = foo://example.com:8042/over/there?name=ferret#nose
Scheme = foo
Domain = example.com
Port = :8042
Path = /over/there
Query = name=ferret
Fragment = nose
 
URL = urn:example:animal:ferret:nose
Scheme = urn
Path = example:animal:ferret:nose
 
URL = jdbc:mysql://test_user:ouupppssss@localhost:3306/sakila?profileSQL=true
Scheme = jdbc
Path = mysql://test_user:ouupppssss@localhost:3306/sakila
Query = profileSQL=true
 
URL = ftp://ftp.is.co.za/rfc/rfc1808.txt
Scheme = ftp
Domain = ftp.is.co.za
Path = /rfc/rfc1808.txt
 
URL = http://www.ietf.org/rfc/rfc2396.txt#header1
Scheme = http
Domain = www.ietf.org
Path = /rfc/rfc2396.txt
Fragment = header1
 
URL = ldap://[2001:db8::7]/c=GB?objectClass=one&objectClass=two
Scheme = ldap
Domain = [2001:db8::7]
Path = /c=GB
Query = objectClass=one&objectClass=two
 
URL = mailto:John.Doe@example.com
Scheme = mailto
Path = John.Doe@example.com
 
URL = news:comp.infosystems.www.servers.unix
Scheme = news
Path = comp.infosystems.www.servers.unix
 
URL = tel:+1-816-555-1212
Scheme = tel
Path = +1-816-555-1212
 
URL = telnet://192.0.2.16:80/
Scheme = telnet
Domain = 192.0.2.16
Port = :80
Path = /
 
URL = urn:oasis:names:specification:docbook:dtd:xml:4.1.2
Scheme = urn
Path = oasis:names:specification:docbook:dtd:xml:4.1.2
 
URL = ssh://alice@example.com
Scheme = ssh
Username = alice
Domain = example.com
 
URL = https://bob:pass@example.com/place
Scheme = https
Username = bob
Password = pass
Domain = example.com
Path = /place
 
URL = http://example.com/?a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
Scheme = http
Domain = example.com
Path = /
Query = a=1&b=2+2&c=3&c=4&d=%65%6e%63%6F%64%65%64
</pre>
9,482

edits