DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

URLを解析する

URL(URI)を解析して、サーバー名、ポート番号、スキーム名、絶対パス、クエリ情報、フラグメント、ユーザー名、パスワードなどの情報を取得することは、その文字列を自分で解析することでも可能ですが、.NET FrameworkではUriクラスを使うと非常に簡単です。

早速ですが、以下に

http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top

というURLを解析する例を示します。

VB.NET
コードを隠すコードを選択
'解析するURL(このURLは実在しません) 
Dim url As String = "http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top"

'Uriオブジェクトを作成 
Dim u As New Uri(url)

'絶対パス 
Console.WriteLine(u.AbsolutePath)
'結果: /vb/bbs.cgi 

'絶対URI 
Console.WriteLine(u.AbsoluteUri)
'結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1#top 

'サーバーのDNS(Domain Name System)ホスト名またはIPアドレスと、ポート番号 
Console.WriteLine(u.Authority)
'結果: www.dobon.net 

'DNSの解決に安全に使用できるエスケープ解除されたホスト名 
Console.WriteLine(u.DnsSafeHost)
'結果: www.dobon.net 

'エスケープフラグメント 
Console.WriteLine(u.Fragment)
'結果: #top 

'サーバーのDNSホスト名またはIPアドレス 
Console.WriteLine(u.Host)
'結果: www.dobon.net 

'ホスト名の型 
Select Case u.HostNameType
    Case UriHostNameType.Basic
        Console.WriteLine("ホストは設定されましたが、型を決定できません。")
        Exit Select
    Case UriHostNameType.Dns
        Console.WriteLine("ホスト名は、ドメイン名システム形式のホスト名です。")
        Exit Select
    Case UriHostNameType.IPv4
        Console.WriteLine("ホスト名は、IP Version 4 形式のホストアドレスです。")
        Exit Select
    Case UriHostNameType.IPv6
        Console.WriteLine("ホスト名は、IP Version 6 形式のホスト アドレスです。")
        Exit Select
    Case UriHostNameType.Unknown
        Console.WriteLine("ホスト名の型が指定されていません。")
        Exit Select
End Select
'結果: ホスト名は、ドメイン名システム形式のホスト名です。 

'絶対インスタンスであるかどうか 
Console.WriteLine(u.IsAbsoluteUri)
'結果: True 

'ポート値がこのスキームの既定のポート値かどうか 
Console.WriteLine(u.IsDefaultPort)
'結果: True 

'ファイルURIかどうか 
Console.WriteLine(u.IsFile)
'結果: False 

'ローカルホストを参照するかどうか 
Console.WriteLine(u.IsLoopback)
'結果: False 

'UNCパスかどうか 
Console.WriteLine(u.IsUnc)
'結果: False 

'Uriコンストラクタに渡された元のURI文字列 
Console.WriteLine(u.OriginalString)
'結果: http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top 

'ローカルオペレーティングシステムでのファイル名表現 
Console.WriteLine(u.LocalPath)
'結果: /vb/bbs.cgi 

'AbsolutePathプロパティとQueryプロパティを疑問符(?)で区切った形式 
Console.WriteLine(u.PathAndQuery)
'結果: /vb/bbs.cgi?id=a%20b&n=1 

'ポート番号 
Console.WriteLine(u.Port)
'結果: 80 

'クエリ情報 
Console.WriteLine(u.Query)
'結果: ?id=a%20b&n=1 

'スキーム名 
Console.WriteLine(u.Scheme)
'結果: http 

'セグメント 
For Each s As String In u.Segments
    Console.WriteLine(vbTab & s)
Next
'結果: 
' / 
' vb/ 
' bbs.cgi 

'Uriインスタンスの作成前に、URI文字列がエスケープされているか 
Console.WriteLine(u.UserEscaped)
'結果: False 

'ユーザー名、パスワードなどのユーザー固有の情報 
Console.WriteLine(u.UserInfo)
'結果: user:pass 

'左端からスキームまで 
Console.WriteLine(u.GetLeftPart(UriPartial.Scheme))
'結果: http:// 

'左端から権限まで 
Console.WriteLine(u.GetLeftPart(UriPartial.Authority))
'結果: http://user:pass@www.dobon.net 

'左端からパスまで 
Console.WriteLine(u.GetLeftPart(UriPartial.Path))
'結果: http://user:pass@www.dobon.net/vb/bbs.cgi 

'左端からクエリまで 
Console.WriteLine(u.GetLeftPart(UriPartial.Query))
'結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1 

'エスケープ解除された正規形式のURI 
Console.WriteLine(u.ToString())
'結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a b&n=1#top
C#
コードを隠すコードを選択
//解析するURL(このURLは実在しません)
string url = "http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top";

//Uriオブジェクトを作成
Uri u = new Uri(url);

//絶対パス 
Console.WriteLine(u.AbsolutePath);
//結果: /vb/bbs.cgi

//絶対URI
Console.WriteLine(u.AbsoluteUri);
//結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1#top

//サーバーのDNS(Domain Name System)ホスト名またはIPアドレスと、ポート番号
Console.WriteLine(u.Authority);
//結果: www.dobon.net

//DNSの解決に安全に使用できるエスケープ解除されたホスト名
Console.WriteLine(u.DnsSafeHost);
//結果: www.dobon.net

//エスケープフラグメント
Console.WriteLine(u.Fragment);
//結果: #top

//サーバーのDNSホスト名またはIPアドレス
Console.WriteLine(u.Host);
//結果: www.dobon.net

//ホスト名の型
switch (u.HostNameType)
{
    case UriHostNameType.Basic:
        Console.WriteLine(
            "ホストは設定されましたが、型を決定できません。");
        break;
    case UriHostNameType.Dns:
        Console.WriteLine(
            "ホスト名は、ドメイン名システム形式のホスト名です。");
        break;
    case UriHostNameType.IPv4:
        Console.WriteLine(
            "ホスト名は、IP Version 4 形式のホストアドレスです。");
        break;
    case UriHostNameType.IPv6:
        Console.WriteLine(
            "ホスト名は、IP Version 6 形式のホスト アドレスです。");
        break;
    case UriHostNameType.Unknown:
        Console.WriteLine("ホスト名の型が指定されていません。");
        break;
}
//結果: ホスト名は、ドメイン名システム形式のホスト名です。

//絶対インスタンスであるかどうか
Console.WriteLine(u.IsAbsoluteUri);
//結果: True

//ポート値がこのスキームの既定のポート値かどうか
Console.WriteLine(u.IsDefaultPort);
//結果: True

//ファイルURIかどうか
Console.WriteLine(u.IsFile);
//結果: False

//ローカルホストを参照するかどうか
Console.WriteLine(u.IsLoopback);
//結果: False

//UNCパスかどうか
Console.WriteLine(u.IsUnc);
//結果: False

//Uriコンストラクタに渡された元のURI文字列
Console.WriteLine(u.OriginalString);
//結果: http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top

//ローカルオペレーティングシステムでのファイル名表現
Console.WriteLine(u.LocalPath);
//結果: /vb/bbs.cgi

//AbsolutePathプロパティとQueryプロパティを疑問符(?)で区切った形式
Console.WriteLine(u.PathAndQuery);
//結果: /vb/bbs.cgi?id=a%20b&n=1

//ポート番号
Console.WriteLine(u.Port);
//結果: 80

//クエリ情報
Console.WriteLine(u.Query);
//結果: ?id=a%20b&n=1

//スキーム名
Console.WriteLine(u.Scheme);
//結果: http

//セグメント
foreach (string s in u.Segments)
    Console.WriteLine("\t" + s);
//結果: 
//    /
//    vb/
//    bbs.cgi

//Uriインスタンスの作成前に、URI文字列がエスケープされているか
Console.WriteLine(u.UserEscaped);
//結果: False

//ユーザー名、パスワードなどのユーザー固有の情報
Console.WriteLine(u.UserInfo);
//結果: user:pass

//左端からスキームまで
Console.WriteLine(u.GetLeftPart(UriPartial.Scheme));
//結果: http://

//左端から権限まで
Console.WriteLine(u.GetLeftPart(UriPartial.Authority));
//結果: http://user:pass@www.dobon.net

//左端からパスまで
Console.WriteLine(u.GetLeftPart(UriPartial.Path));
//結果: http://user:pass@www.dobon.net/vb/bbs.cgi

//左端からクエリまで
Console.WriteLine(u.GetLeftPart(UriPartial.Query));
//結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1

//エスケープ解除された正規形式のURI 
Console.WriteLine(u.ToString());
//結果: http://user:pass@www.dobon.net/vb/bbs.cgi?id=a b&n=1#top

Uriクラスのプロパティのまとめ

上記の例のように、"http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top"を指定して作成したUriオブジェクトのプロパティやメソッドが返す値を表にまとめると、以下のようになります。

プロパティまたはメソッド 説明
AbsolutePath 絶対パス /vb/bbs.cgi
AbsoluteUri 絶対URI http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1#top
Authority サーバーのDNS(Domain Name System)ホスト名またはIPアドレスと、ポート番号。ポート番号はスキームの既定でない場合のみ付加される(例えば、"www.dobon.net:8080")。予約文字はエスケープされる。 www.dobon.net
DnsSafeHost DNSの解決に安全に使用できるエスケープ解除されたホスト名。IPv6アドレスの場合、角かっこ([])が削除され、さらにScopeIdプロパティが設定されている時はスコープが付加される。(.NET Framework 2.0で追加) www.dobon.net
Fragment エスケープフラグメント #top
Host サーバーのDNSホスト名またはIPアドレス。Authorityと違い、ポート番号を含まない。 www.dobon.net
HostNameType ホスト名の型。Dnsは、ドメイン名システム形式。IPv4は、IP Version 4 形式。IPv6は、IP Version 6 形式。Basicは、ホストは設定されたが、型を決定できない。Unknownは、型が指定されていない。 UriHostNameType.Dns
IsAbsoluteUri 絶対インスタンスとして解析できるか(.NET Framework 2.0で追加) True
IsDefaultPort ポート値がこのスキームの既定のポート値かどうか。例えば、スキームが"http"ならばポート値が80の場合にTrue。 True
IsFile ファイルURIかどうか。SchemeプロパティがUri.UriSchemeFileフィールド("file")と等しい場合にTrue。 False
IsLoopback ローカルホストを参照するかどうか。"127.0.0.1"、"loopback"、または"localhost"のいずれかか、ホスト情報が指定されていない場合("file:///C:Dir/file.txt"など)にTrue。 False
IsUnc UNCパスかどうか。"\\server\folder"などのようなパスか、スキームが"file://"でホスト構成要素を指定している場合にTrue。 False
LocalPath ローカルオペレーティングシステムでのファイル名表現。エスケープが解除される。パスがWindowsファイルパスとして認識される場合は、"/"が"\"に置換される。 /vb/bbs.cgi
OriginalString Uriコンストラクタに渡された元のURI文字列(.NET Framework 2.0で追加) http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top
PathAndQuery AbsolutePathプロパティとQueryプロパティを疑問符(?)で区切った形式 /vb/bbs.cgi?id=a%20b&n=1
Port ポート番号。URI内にポートが指定されていない場合は、プロトコルの既定値。既定のポート番号がない場合は、-1。 80
Query クエリ情報 ?id=a%20b&n=1
Scheme スキーム名 http
Segments URIを構成するパスセグメント。文字列の配列を返す。 /
vb/
bbs.cgi
UserEscaped Uriインスタンスの作成前に、URI文字列がエスケープされているか(コンストラクタのdontEscapeパラメーターがTrueに設定されていたか)。 False
UserInfo ユーザー名、パスワードなどのユーザー固有の情報 user:pass
GetLeftPart(UriPartial.Scheme) 左端からスキームまで http://
GetLeftPart(UriPartial.Authority) 左端から権限まで http://user:pass@www.dobon.net
GetLeftPart(UriPartial.Path) 左端からパスまで http://user:pass@www.dobon.net/vb/bbs.cgi
GetLeftPart(UriPartial.Query) 左端からクエリまで(.NET Framework 2.0で追加) http://user:pass@www.dobon.net/vb/bbs.cgi?id=a%20b&n=1
ToString() エスケープ解除された正規形式のURI http://user:pass@www.dobon.net/vb/bbs.cgi?id=a b&n=1#top

Uriコンストラクタで行われるURLエンコードとデコードについて

Uriクラスは、与えられたURLを正規形式で格納するために、URLにASCII文字以外の文字が含まれている場合は、その文字をコンストラクタでURLエンコード(エスケープ)します。

より正確に言うと、ASCII文字以外の文字ではなく、.NET Framework 4.5以降ではRFC3986およびRFC3987の非予約文字と予約文字以外の文字、それ以前ではRFC2396の非予約文字と予約文字以外の文字をURLエンコードしているようです。URLエンコードについて詳しくは、「URLエンコード、URLデコードを行う」をご覧ください。

補足:必ず非予約文字と予約文字以外の文字がエンコードされる訳ではなく、スキームや、文字のある場所などによってエンコードする文字が変わるようです。

例えば次のようなコードによって、どのようにURLエンコードが行われているかを確認することができます。なおここで紹介している結果は、.NET Framework 4.5でのものです。

VB.NET
コードを隠すコードを選択
Dim url As String = "http://www.dobon.net/あ/%26.cgi" & _
    "?id=!()_-*.aA0 ?$%&|@\/#[]{}<>+=^~""'`;:,"

'Uriオブジェクトを作成
Dim u As New Uri(url)

Console.WriteLine(u.AbsolutePath)
' /%E3%81%82/%26.cgi

Console.WriteLine(u.Query)
' ?id=!()_-*.aA0%20?$%25&%7C@%5C/

Console.WriteLine(u.Fragment)
' #[]%7B%7D%3C%3E+=%5E~%22'%60;:,
C#
コードを隠すコードを選択
string url = "http://www.dobon.net/あ/%26.cgi" +
    "?id=!()_-*.aA0 ?$%&|@\\/#[]{}<>+=^~\"'`;:,";

//Uriオブジェクトを作成
Uri u = new Uri(url);

Console.WriteLine(u.AbsolutePath);
// /%E3%81%82/%26.cgi

Console.WriteLine(u.Query);
// ?id=!()_-*.aA0%20?$%25&%7C@%5C/

Console.WriteLine(u.Fragment);
// #[]%7B%7D%3C%3E+=%5E~%22'%60;:,

またUriクラスは、与えられたURLに「%xx」形式の16進数値が含まれている時、その一部をコンストラクタでデコードしているようです。私が試したところでは、半角英数字と「!()_-*.[]~':」(.NET Framework 4.0では、半角英数字と「!()_-*.~':」)(つまり、非予約文字すべてと、予約文字の一部)の「%xx」表現が含まれている時、これらがデコードされました。

VB.NET
コードを隠すコードを選択
Dim url As String = "http://www.dobon.net/a.cgi" & _
    "?%21%28%29%5F%2D%2A%2E%61%41%30%5B%5D%7E%27%3A"

'Uriオブジェクトを作成
Dim u As New Uri(url)

Console.WriteLine(u.Query)
' ?!()_-*.aA0[]~':
C#
コードを隠すコードを選択
string url = "http://www.dobon.net/a.cgi" +
    "?%21%28%29%5F%2D%2A%2E%61%41%30%5B%5D%7E%27%3A";

//Uriオブジェクトを作成
Uri u = new Uri(url);

Console.WriteLine(u.Query);
// ?!()_-*.aA0[]~':

AbsoluteUriプロパティ、OriginalStringプロパティ、ToStringメソッドの違い

MSDNの「Uri.OriginalString プロパティ」と「Uri.ToString メソッド」の説明を総合すると、ToStringメソッドは、#、?、%以外のすべての文字のエスケープを解除し、AbsoluteUriプロパティは一切エスケープ解除をしないと解釈できます。しかし、ToStringメソッドについては、実際は少し違うようです。

実際に試してみると、ToStringメソッドは「?#$%&@\/+=;,」の「%xx」表現である「%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C」をデコードしませんでした。また、「+」をスペースに変換しませんでした。

VB.NET
コードを隠すコードを選択
Dim url As String = "http://www.dobon.net/bbs.cgi?" & _
    "%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C%E3%81%82+"

'Uriオブジェクトを作成
Dim u As New Uri(url)

Console.WriteLine(u.AbsoluteUri)
'http://www.dobon.net/bbs.cgi?%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C%E3%81%82+

Console.WriteLine(u.ToString())
'http://www.dobon.net/bbs.cgi?%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2Cあ+
C#
コードを隠すコードを選択
string url = "http://www.dobon.net/bbs.cgi?" +
    "%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C%E3%81%82+";

//Uriオブジェクトを作成
Uri u = new Uri(url);

Console.WriteLine(u.AbsoluteUri);
//http://www.dobon.net/bbs.cgi?%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C%E3%81%82+

Console.WriteLine(u.ToString());
//http://www.dobon.net/bbs.cgi?%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2Cあ+

.NET Framework 2.0から追加されたOriginalStringプロパティは、基本的には、Uriオブジェクトを作成するときに指定された文字列をそのまま返します。

UriコンストラクタではURLエンコードとデコードが行われると説明しましたが、それ以外にも、ポート番号がスキームの既定のポート番号と同じならば削除するなどの変換が行われます。しかしOriginalStringプロパティは、そのような変換が行われる前の文字列を返します。

以下の例でその違いをご確認ください。

VB.NET
コードを隠すコードを選択
Dim url As String = "http://www.dobon.net:80/あ/%41.cgi" & _
    "?id=!()_-*.aA0 ?$%&|@\/#[]{}<>+=^~""'`;:,"

'Uriオブジェクトを作成
Dim u As New Uri(url)

Console.WriteLine(u.AbsoluteUri)
'http://www.dobon.net/%E3%81%82/A.cgi?id=!()_-*.aA0%20?$%25&%7C@%5C/#[]
'%7B%7D%3C%3E+=%5E~%22'%60;:,

Console.WriteLine(u.ToString())
'http://www.dobon.net/あ/A.cgi?id=!()_-*.aA0 ?$%25&|@\/#[]{}<>+=^~"'`;:,

Console.WriteLine(u.OriginalString)
'http://www.dobon.net:80/あ/%41.cgi?id=!()_-*.aA0 ?$%&|@\/#[]{}<>+=^~"'`;:,
C#
コードを隠すコードを選択
string url = "http://www.dobon.net:80/あ/%41.cgi" +
    "?id=!()_-*.aA0 ?$%&|@\\/#[]{}<>+=^~\"'`;:,";

//Uriオブジェクトを作成
Uri u = new Uri(url);

Console.WriteLine(u.AbsoluteUri);
//http://www.dobon.net/%E3%81%82/A.cgi?id=!()_-*.aA0%20?$%25&%7C@%5C/#[]
//%7B%7D%3C%3E+=%5E~%22'%60;:,

Console.WriteLine(u.ToString());
//http://www.dobon.net/あ/A.cgi?id=!()_-*.aA0 ?$%25&|@\/#[]{}<>+=^~"'`;:,

Console.WriteLine(u.OriginalString);
//http://www.dobon.net:80/あ/%41.cgi?id=!()_-*.aA0 ?$%&|@\/#[]{}<>+=^~"'`;:,

HostとDnsSafeHostプロパティの違い

HostとDnsSafeHostプロパティについては、「ホスト名(ドメイン名)をPunycodeに変換(エンコード、デコード)する」をご覧ください。

Uri.GetComponentsメソッドを使用する方法

今まで紹介してきたUriクラスのプロパティで取得できる情報のほとんどをUri.GetComponentsメソッドを使って取得することもできます。このメソッドは、.NET Framework 2.0以降で使用できます。

GetComponentsメソッドを使うと、例えばスキームとホスト名とパスを連結した文字列を取得するというように、複数の部分を一度に取得することができます。どの部分を取得するかは、UriComponents列挙体値のビット組み合わせで指定します。

またGetComponentsメソッドでは、URLエンコードを行うかを指定することもできます。UriFormat列挙体のUriEscapedを指定すればエンコードし、Unescapedを指定すればエンコードしません。SafeUnescapedを指定すると、UriComponentsで指定された部分で意味が予約されていれば、"%"、"#"、"?"、"/"、"\"、"@"がエンコードされます。

以下にGetComponentsメソッドの使用例を示します。

VB.NET
コードを隠すコードを選択
'解析するURL(このURLは実在しません)
Dim url As String = _
    "http://user:pass@www.dobon.net:80/a/b.cgi?id=a%20b&%?/\@##top"

'Uriオブジェクトを作成
Dim u As New Uri(url)

'スキームとパスを取得する
Console.WriteLine( _
    u.GetComponents(UriComponents.Scheme Or UriComponents.Path, _
                    UriFormat.SafeUnescaped))
'http:///a/b.cgi

'クエリーを取得する
'URLエンコードしない
Console.WriteLine( _
    u.GetComponents(UriComponents.Query, UriFormat.Unescaped))
'id=a b&%?/\@

'URLエンコードする
Console.WriteLine( _
    u.GetComponents(UriComponents.Query, UriFormat.UriEscaped))
'id=a%20b&%25?/%5C@

'意味が予約されている文字だけをURLエンコードする
Console.WriteLine( _
    u.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped))
'id=a b&%25?/\@
C#
コードを隠すコードを選択
//解析するURL(このURLは実在しません)
string url = "http://user:pass@www.dobon.net:80/a/b.cgi?id=a%20b&%?/\\@##top";

//Uriオブジェクトを作成
Uri u = new Uri(url);

//スキームとパスを取得する
Console.WriteLine(
    u.GetComponents(UriComponents.Scheme | UriComponents.Path,
        UriFormat.SafeUnescaped));
//http:///a/b.cgi

//クエリーを取得する
//URLエンコードしない
Console.WriteLine(
    u.GetComponents(UriComponents.Query, UriFormat.Unescaped));
//id=a b&%?/\@

//URLエンコードする
Console.WriteLine(
    u.GetComponents(UriComponents.Query, UriFormat.UriEscaped));
//id=a%20b&%25?/%5C@

//意味が予約されている文字だけをURLエンコードする
Console.WriteLine(
    u.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped));
//id=a b&%25?/\@
  • 履歴:
  • 2006/11/20 表を追加。
  • 2007/10/3 表中のGetLeftPart(UriPartial.Authority)を修正。GetLeftPart(UriPartial.Query)を追加。
  • 2009/1/9 説明を追加。
  • 2013/7/28 「Uri.GetComponentsメソッドを使用する方法」を追加。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • .NET Tipsをご利用いただく際は、注意事項をお守りください。