URL(URI)を解析して、サーバー名、ポート番号、スキーム名、絶対パス、クエリ情報、フラグメント、ユーザー名、パスワードなどの情報を取得することは、その文字列を自分で解析することでも可能ですが、.NET FrameworkではUriクラスを使うと非常に簡単です。
早速ですが、以下に
http://user:pass@www.dobon.net:80/vb/bbs.cgi?id=a%20b&n=1#top
というURLを解析する例を示します。
'解析する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
//解析する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
上記の例のように、"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を正規形式で格納するために、URLにASCII文字以外の文字が含まれている場合は、その文字をコンストラクタでURLエンコード(エスケープ)します。
より正確に言うと、ASCII文字以外の文字ではなく、.NET Framework 4.5以降ではRFC3986およびRFC3987の非予約文字と予約文字以外の文字、それ以前ではRFC2396の非予約文字と予約文字以外の文字をURLエンコードしているようです。URLエンコードについて詳しくは、「URLエンコード、URLデコードを行う」をご覧ください。
補足:必ず非予約文字と予約文字以外の文字がエンコードされる訳ではなく、スキームや、文字のある場所などによってエンコードする文字が変わるようです。
例えば次のようなコードによって、どのようにURLエンコードが行われているかを確認することができます。なおここで紹介している結果は、.NET Framework 4.5でのものです。
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;:,
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」表現が含まれている時、これらがデコードされました。
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[]~':
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[]~':
MSDNの「Uri.OriginalString プロパティ」と「Uri.ToString メソッド」の説明を総合すると、ToStringメソッドは、#、?、%以外のすべての文字のエスケープを解除し、AbsoluteUriプロパティは一切エスケープ解除をしないと解釈できます。しかし、ToStringメソッドについては、実際は少し違うようです。
実際に試してみると、ToStringメソッドは「?#$%&@\/+=;,」の「%xx」表現である「%3F%23%24%25%26%40%5C%2F%2B%3D%3B%2C」をデコードしませんでした。また、「+」をスペースに変換しませんでした。
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あ+
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プロパティは、そのような変換が行われる前の文字列を返します。
以下の例でその違いをご確認ください。
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 ?$%&|@\/#[]{}<>+=^~"'`;:,
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プロパティについては、「ホスト名(ドメイン名)をPunycodeに変換(エンコード、デコード)する」をご覧ください。
今まで紹介してきたUriクラスのプロパティで取得できる情報のほとんどをUri.GetComponentsメソッドを使って取得することもできます。このメソッドは、.NET Framework 2.0以降で使用できます。
GetComponentsメソッドを使うと、例えばスキームとホスト名とパスを連結した文字列を取得するというように、複数の部分を一度に取得することができます。どの部分を取得するかは、UriComponents列挙体値のビット組み合わせで指定します。
またGetComponentsメソッドでは、URLエンコードを行うかを指定することもできます。UriFormat列挙体のUriEscapedを指定すればエンコードし、Unescapedを指定すればエンコードしません。SafeUnescapedを指定すると、UriComponentsで指定された部分で意味が予約されていれば、"%"、"#"、"?"、"/"、"\"、"@"がエンコードされます。
以下にGetComponentsメソッドの使用例を示します。
'解析する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?/\@
//解析する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?/\@
注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。