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

URLエンコード、URLデコードを行う

ここでは、文字列をURLエンコード(パーセントエンコーディング、URLエスケープ、URL符号化、パーセント符号化、百分率符号化)する方法と、URLデコードする方法を紹介します。

URLエンコードを行う

HttpUtility.UrlEncodeメソッド

HttpUtilityクラス(System.Web名前空間)のUrlEncodeメソッドを使ってURLエンコードを行うことができます。HttpUtilityクラスを使用するには、System.Web.dllを参照設定に追加する必要があります。

以下に、HttpUtility.UrlEncodeメソッドが文字列をどのようにエンコードするかを調べるコードを示します。

VB.NET
コードを隠すコードを選択
'URLエンコードする文字列
Dim str As String = "!()_-*.aA0 ?#$%&|@\/[]{}<>+=^~""'`;:,あ"

'URLエンコードする
Dim urlEnc As String = System.Web.HttpUtility.UrlEncode(str)

'結果を表示する
Console.WriteLine(urlEnc)
'!()_-*.aA0+%3f%23%24%25%26%7c%40%5c%2f%5b%5d%7b%7d%3c%3e%2b%3d%5e
'%7e%22%27%60%3b%3a%2c%e3%81%82
C#
コードを隠すコードを選択
//URLエンコードする文字列
string str = "!()_-*.aA0 ?#$%&|@\\/[]{}<>+=^~\"'`;:,あ";

//URLエンコードする
string urlEnc = System.Web.HttpUtility.UrlEncode(str);

//結果を表示する
Console.WriteLine(urlEnc);
//!()_-*.aA0+%3f%23%24%25%26%7c%40%5c%2f%5b%5d%7b%7d%3c%3e%2b%3d%5e
//%7e%22%27%60%3b%3a%2c%e3%81%82

このように、UrlEncodeメソッドがエンコードするのは、英字(大文字・小文字)、数字、「!」(感嘆符)、「(」、「)」(丸かっこ)、「_」(アンダースコア)、「-」(ハイフン)、「*」(アスタリスク)、「.」(ピリオド)以外の文字です。

また、半角スペースを「+」にエンコードします。この点は、「application/x-www-form-urlencoded」に従っています。

16進数表現は、小文字です。

UrlEncodeメソッドでは、文字コードを指定しないとUTF-8としてエンコードします。文字コードを指定する時は、2番目のパラメータにEncodingオブジェクトを指定します。または、「文字列を文字コードを指定してバイト型配列のデータに変換する」のように文字列をバイト型配列に変換してからUrlEncodeメソッドでURLエンコードすることもできます。

以下の例では、Shift-JISでエンコードしています。

VB.NET
コードを隠すコードを選択
Dim str As String = "あいうえお+- &!"

'Shift-JISでURLエンコードする
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift_jis")
Dim urlEncSjis As String = System.Web.HttpUtility.UrlEncode(str, enc)

Console.WriteLine(urlEncSjis)
'%82%a0%82%a2%82%a4%82%a6%82%a8%2b-+%26!
C#
コードを隠すコードを選択
string str = "あいうえお+- &!";

//Shift-JISでURLエンコードする
System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis");
string urlEncSjis = System.Web.HttpUtility.UrlEncode(str, enc);

Console.WriteLine(urlEncSjis);
//%82%a0%82%a2%82%a4%82%a6%82%a8%2b-+%26!

Uri.EscapeDataStringとUri.EscapeUriStringメソッド

.NET Framework 2.0以降では、Uri.EscapeDataStringUri.EscapeUriStringメソッドでもURLエンコードができます。まずはこれらのメソッドがどのようにエンコードするか、次のようなコードで確かめてみましょう。

注意:後ほど詳しく説明しますが、これらのメソッドのデフォルトでのエンコードの仕方は、.NET Framework 4.0以前と4.5以降で異なります。ここでの説明は4.5以降についてです。
VB.NET
コードを隠すコードを選択
Dim str As String = "!()_-*.aA0 ?#$%&|@\/[]{}<>+=^~""'`;:,あ"

'EscapeDataStringでURLエンコードする
Dim escapeDataString As String = Uri.EscapeDataString(str)
Console.WriteLine(escapeDataString)
'%21%28%29_-%2A.aA0%20%3F%23%24%25%26%7C%40%5C%2F%5B%5D%7B%7D%3C%3E%2B
'%3D%5E~%22%27%60%3B%3A%2C%E3%81%82

'EscapeUriStringでURLエンコードする
Dim escapeUriString As String = Uri.EscapeUriString(str)
Console.WriteLine(escapeUriString)
'!()_-*.aA0%20?#$%25&%7C@%5C/[]%7B%7D%3C%3E+=%5E~%22'%60;:,%E3%81%82
C#
コードを隠すコードを選択
string str = "!()_-*.aA0 ?#$%&|@\\/[]{}<>+=^~\"'`;:,あ";

//EscapeDataStringでURLエンコードする
string escapeDataString = Uri.EscapeDataString(str);
Console.WriteLine(escapeDataString);
//%21%28%29_-%2A.aA0%20%3F%23%24%25%26%7C%40%5C%2F%5B%5D%7B%7D%3C%3E%2B
//%3D%5E~%22%27%60%3B%3A%2C%E3%81%82

//EscapeUriStringでURLエンコードする
string escapeUriString = Uri.EscapeUriString(str);
Console.WriteLine(escapeUriString);
//!()_-*.aA0%20?#$%25&%7C@%5C/[]%7B%7D%3C%3E+=%5E~%22'%60;:,%E3%81%82

この結果を見ると、両者とも半角スペースを「%20」にエンコードしています。これは、RFC3986に従ったエンコード方法です。16進数表現は大文字です。文字コードはUTF-8です。

EscapeDataStringメソッドは、英字(大文字・小文字)と数字以外に、「_」(アンダースコア)、「-」(ハイフン)、「.」(ピリオド)、「~」(チルダ)をエンコードしせん。つまり、RFC3986の非予約文字(Unreserved Characters)以外をエンコードしています。

EscapeUriStringメソッドはそれに加えて、「!」、「(」、「)」、「*」、「.」、「?」、「#」、「$」、「&」、「@」、「/」、「[」、「]」、「+」、「=」、「'」、「;」、「:」、「,」をエンコードしません。つまり、RFC3986の非予約文字と予約文字(Reserved Characters)以外をエンコードします。予約文字は、URLの区切りなどの特別な意味を持っている文字ですので、URLの基本的な構造を崩さずにURLエンコードしたい時は、EscapeUriStringメソッドを使います。一方、URL全体をURLエンコードしてクエリー文字列を作成する時には、使用できません。

よって、基本的には、RFC3986に基づいたURLエンコードを行うには、EscapeDataStringメソッドを使います。特別な事情で予約文字をエンコードしてはいけない場合のみ、EscapeUriStringメソッドを使います。

EscapeDataStringとEscapeUriStringの.NET Framework 4.5以上と未満での違い

上記のEscapeUriStringとEscapeDataStringメソッドの説明は.NET Framework 4.5以降のもので、4.0以前では異なります。4.0以前では、RFC2396に準拠した方法でエンコードを行います。つまり、EscapeDataStringメソッドはRFC2396の非予約文字(英字数字と「-_.!~*'()」)以外をエンコードし、EscapeUriStringメソッドはRFC2396の非予約文字と予約文字(「;/?:@&=+$,」)以外をエンコードします。

4.0と4.5のEscapeDataStringメソッドを比べると、4.5では「!()*'」をエンコードします。4.0と4.5のEscapeUriStringメソッドを比べると、4.5では「[]」をエンコードしません。

MSDNのEscapeUriStringとEscapeDataStringメソッドの説明によると、国際化リソース識別子(IRI)または国際化ドメイン名(IDN)解析が有効になっている場合は、RFC3986およびRFC3987に従って文字列がエスケープされ、無効になっている場合は、RFC2396に従ってエスケープされるそうです。IRIのサポートは.NET Framework 2.0 SP1から提供されましたが、IRI解析がデフォルトで有効なのは4.5からで、それより前では無効になっています(「.NET Framework 4.5 のアプリケーションの互換性」より)。そのため、.NET 4.0と4.5でこのような違いが出るのだろうと思われます。

.NET 4.0以前でIRI解析を有効にするには、app.config(または、machine.config)ファイルに設定を追加します。この方法は、「ドメイン名(ホスト名)をPunycodeに変換(エンコード、デコード)する」で説明しています。しかし、私が試した限りでは、IRIを有効にしてもEscapeUriStringとEscapeDataStringメソッドはRFC2396に従ったエンコードしかしませんでした。

.NETのバージョンによらずRFC3986に基づいたURLエンコードを行う

Uri.EscapeDataStringとEscapeUriStringを使わずにRFC3986に基づいたURLエンコードを行うコードを書いてみました。蛇足として、UTF-8以外の文字コードも指定できるようにしています。

VB.NET
コードを隠すコードを選択
Public Class RFC3986Uri
    Public Shared ReadOnly UnreservedCharacters As String = "-._~"
    Public Shared ReadOnly ReservedCharacters As String = _
        UnreservedCharacters + ":/?#[]@!$&'()*+,;="

    ''' <summary>
    ''' RFC3986に基づいてURLエンコードを行います。
    ''' </summary>
    ''' <param name="stringToEscape">
    ''' URLエンコードする文字列。
    ''' </param>
    ''' <param name="escapeEncoding">
    ''' エンコード方式を指定するEncoding オブジェクト。
    ''' </param>
    ''' <returns>
    ''' URLエンコードされた文字列。
    ''' </returns>
    Public Shared Function EscapeDataString( _
            ByVal stringToEscape As String, _
            ByVal escapeEncoding As System.Text.Encoding) As String
        Return PercentEncodeString( _
            stringToEscape, UnreservedCharacters, escapeEncoding)
    End Function
    Public Shared Function EscapeDataString( _
            ByVal stringToEscape As String) As String
        Return EscapeDataString(stringToEscape, System.Text.Encoding.UTF8)
    End Function

    ''' <summary>
    ''' RFC3986に基づいてURI文字列のURLエンコードを行います。
    ''' </summary>
    ''' <param name="stringToEscape">
    ''' URLエンコードする文字列。
    ''' </param>
    ''' <param name="escapeEncoding">
    ''' エンコード方式を指定するEncoding オブジェクト。
    ''' </param>
    ''' <returns>
    ''' URLエンコードされた文字列。
    ''' </returns>
    Public Shared Function EscapeUriString( _
            ByVal stringToEscape As String, _
            ByVal escapeEncoding As System.Text.Encoding) As String
        Return PercentEncodeString( _
            stringToEscape, ReservedCharacters, escapeEncoding)
    End Function
    Public Shared Function EscapeUriString( _
            ByVal stringToEscape As String) As String
        Return EscapeUriString(stringToEscape, System.Text.Encoding.UTF8)
    End Function

    Friend Shared Function PercentEncodeString( _
            ByVal stringToEscape As String, _
            ByVal dontEscapeCharacters As String, _
            ByVal escapeEncoding As System.Text.Encoding) As String
        Dim encodedString As New System.Text.StringBuilder()

        For Each c As Char In stringToEscape
            If ("0"c <= c AndAlso c <= "9"c) OrElse _
                ("a"c <= c AndAlso c <= "z"c) OrElse _
                ("A"c <= c AndAlso c <= "Z"c) OrElse _
                (0 <= dontEscapeCharacters.IndexOf(c)) Then
                'エンコードしない文字の場合
                encodedString.Append(c)
            Else
                'エンコードする文字の場合
                encodedString.Append(HexEscape(c, escapeEncoding))
            End If
        Next

        Return encodedString.ToString()
    End Function

    ''' <summary>
    ''' 指定した文字のパーセントエンコーディング(百分率符号化)を行います。
    ''' </summary>
    ''' <param name="character">
    ''' パーセントエンコーディングする文字。
    ''' </param>
    ''' <param name="escapeEncoding">
    ''' エンコード方式を指定するEncoding オブジェクト。
    ''' </param>
    ''' <returns>
    ''' パーセントエンコーディングされた文字列。
    ''' </returns>
    Public Shared Function HexEscape( _
            ByVal character As Char, _
            ByVal escapeEncoding As System.Text.Encoding) As String
        If 255 < AscW(character) Then
            'characterが255を超えるときはUri.HexEscapeが使えない
            Dim buf As New System.Text.StringBuilder()
            Dim characterBytes As Byte() = _
                escapeEncoding.GetBytes(character.ToString())
            For Each b As Byte In characterBytes
                buf.AppendFormat("%{0:X2}", b)
            Next

            Return buf.ToString()
        End If

        Return Uri.HexEscape(character)
    End Function
End Class
C#
コードを隠すコードを選択
public class RFC3986Uri
{
    public static readonly string UnreservedCharacters =
        "-._~";
    public static readonly string ReservedCharacters =
        UnreservedCharacters + ":/?#[]@!$&'()*+,;=";

    /// <summary>
    /// RFC3986に基づいてURLエンコードを行います。
    /// </summary>
    /// <param name="stringToEscape">
    /// URLエンコードする文字列。
    /// </param>
    /// <param name="escapeEncoding">
    /// エンコード方式を指定するEncoding オブジェクト。
    /// </param>
    /// <returns>
    /// URLエンコードされた文字列。
    /// </returns>
    public static string EscapeDataString(string stringToEscape,
        System.Text.Encoding escapeEncoding)
    {
        return PercentEncodeString(
            stringToEscape, UnreservedCharacters, escapeEncoding);
    }
    public static string EscapeDataString(string stringToEscape)
    {
        return EscapeDataString(stringToEscape, System.Text.Encoding.UTF8);
    }

    /// <summary>
    /// RFC3986に基づいてURI文字列のURLエンコードを行います。
    /// </summary>
    /// <param name="stringToEscape">
    /// URLエンコードする文字列。
    /// </param>
    /// <param name="escapeEncoding">
    /// エンコード方式を指定するEncoding オブジェクト。
    /// </param>
    /// <returns>
    /// URLエンコードされた文字列。
    /// </returns>
    public static string EscapeUriString(string stringToEscape,
        System.Text.Encoding escapeEncoding)
    {
        return PercentEncodeString(
            stringToEscape, ReservedCharacters, escapeEncoding);
    }
    public static string EscapeUriString(string stringToEscape)
    {
        return EscapeUriString(stringToEscape, System.Text.Encoding.UTF8);
    }

    internal static string PercentEncodeString(string stringToEscape,
        string dontEscapeCharacters,
        System.Text.Encoding escapeEncoding)
    {
        System.Text.StringBuilder encodedString =
            new System.Text.StringBuilder();

        foreach (char c in stringToEscape)
        {
            if (('0' <= c && c <= '9') ||
                ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') ||
                (0 <= dontEscapeCharacters.IndexOf(c)))
            {
                //エンコードしない文字の場合
                encodedString.Append(c);
            }
            else
            {
                //エンコードする文字の場合
                encodedString.Append(HexEscape(c, escapeEncoding));
            }
        }

        return encodedString.ToString();
    }

    /// <summary>
    /// 指定した文字のパーセントエンコーディング(百分率符号化)を行います。
    /// </summary>
    /// <param name="character">
    /// パーセントエンコーディングする文字。
    /// </param>
    /// <param name="escapeEncoding">
    /// エンコード方式を指定するEncoding オブジェクト。
    /// </param>
    /// <returns>
    /// パーセントエンコーディングされた文字列。
    /// </returns>
    public static string HexEscape(char character,
        System.Text.Encoding escapeEncoding)
    {
        if (255 < (int)character)
        {
            //characterが255を超えるときはUri.HexEscapeが使えない
            System.Text.StringBuilder buf = new System.Text.StringBuilder();
            byte[] characterBytes =
                escapeEncoding.GetBytes(character.ToString());
            foreach (byte b in characterBytes)
            {
                buf.AppendFormat("%{0:X2}", b);
            }

            return buf.ToString();
        }

        return Uri.HexEscape(character);
    }
}

URLエンコードのまとめ

以上の説明をまとめます。

  • .NET Framework 4.5以降で、RFC3986に基づいたURLエンコードを行う時は、Uri.EscapeDataStringメソッドを使います。RFC3986に基づいたURLエンコードで、予約文字をエンコードしない時は、Uri.EscapeUriStringメソッドを使います。ただし、.NET Framework 2.0〜4.0では、これらのメソッドはRFC2396に基づいたエンコードを行います。
  • .NET Framework 1.1以前では、HttpUtility.UrlEncodeメソッドを使ってURLエンコードができます。
  • Uri.EscapeUriStringとUri.EscapeDataStringメソッドは、半角スペースを「%20」にエンコードします。HttpUtility.UrlEncodeメソッドは、半角スペースを「+」にエンコードします。

URLデコードを行う

HttpUtility.UrlDecodeメソッド

URLデコードを行うには、HttpUtilityクラスのUrlDecodeメソッドを使います。HttpUtilityクラスを使用するには、System.Web.dllを参照設定に追加する必要があります。

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

VB.NET
コードを隠すコードを選択
Dim urlEnc As String = "%2b%2d%28%20+%29%e3%81%82"

'URLデコードする
Dim urlDec As String = System.Web.HttpUtility.UrlDecode(urlEnc)

Console.WriteLine(urlDec)
'「+-(  )あ」と表示される
C#
コードを隠すコードを選択
string urlEnc = "%2b%2d%28%20+%29%e3%81%82";

//URLデコードする
string urlDec = System.Web.HttpUtility.UrlDecode(urlEnc);

Console.WriteLine(urlDec);
//「+-(  )あ」と表示される

UrlDecodeメソッドは、文字コードを指定しないとUTF-8としてデコードします。文字コードを指定する時は、2番目のパラメータにEncodingオブジェクトを指定します。

VB.NET
コードを隠すコードを選択
Dim urlEncSjis As String = "%2b%2d%28%20%29%82%a0"

'Shift-JISでURLデコードする
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift_jis")
Dim urlDecSjis As String = System.Web.HttpUtility.UrlDecode(urlEncSjis, enc)

Console.WriteLine(urlDecSjis)
'「+-( )あ」と表示される
C#
コードを隠すコードを選択
string urlEncSjis = "%2b%2d%28%20%29%82%a0";

//Shift-JISでURLデコードする
System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis");
string urlDecSjis = System.Web.HttpUtility.UrlDecode(urlEncSjis, enc);

Console.WriteLine(urlDecSjis);
//「+-( )あ」と表示される

Uri.UnescapeDataStringメソッド

.NET Framework 2.0以降では、Uri.UnescapeDataStringメソッドを使ってURLデコードすることもできます。ただし、このメソッドは「+」を半角スペースに変換しませんので、注意が必要です。

また、文字コードはUTF-8にだけ対応しています。

以下にUnescapeDataStringメソッドを使った例を示します。

VB.NET
コードを隠すコードを選択
Dim urlEnc As String = "%2b%2d%28%20+%29%e3%81%82"

'URLデコードする
Dim urlDec As String = Uri.UnescapeDataString(urlEnc)

Console.WriteLine(urlDec)
'「+-( +)あ」と表示される

'「+」が半角スペースにデコードされるようにするには、次のようにする
Dim urlDec2 As String = Uri.UnescapeDataString(urlEnc.Replace("+"c, " "c))

Console.WriteLine(urlDec2)
'「+-(  )あ」と表示される
C#
コードを隠すコードを選択
string urlEnc = "%2b%2d%28%20+%29%e3%81%82";

//URLデコードする
string urlDec = Uri.UnescapeDataString(urlEnc);

Console.WriteLine(urlDec);
//「+-( +)あ」と表示される

//「+」が半角スペースにデコードされるようにするには、次のようにする
string urlDec2 = Uri.UnescapeDataString(urlEnc.Replace('+', ' '));

Console.WriteLine(urlDec2);
//「+-(  )あ」と表示される

URLデコードのまとめ

以上の説明をまとめます。

  • URLデコードを行うには、HttpUtility.UrlDecodeメソッドを使います。
  • Uri.UnescapeDataStringメソッドは「+」を半角スペースに変換しないため、URLデコードに使用すべきではありません。どうしても使用する場合は、デコードする文字列の「+」を半角スペース(あるいは、「%20」)に変換してから使用します。

上記以外の方法

HttpServerUtilityクラスのインスタンスメソッドであるUrlEncodeメソッドとUrlDecodeメソッドでもURLエンコードとデコードができます。これらのメソッドは内部でHttpUtilityクラスのUrlEncodeメソッドとUrlDecodeメソッドを呼び出していますので、結果はHttpUtilityクラスを使った時と同じです。

.NET Framework 1.1以降で使用できるHttpUtility.UrlPathEncodeメソッドは、非ASCII文字と半角スペースだけをエンコードします。半角スペースは「%20」にエンコードします。また、エンコードする文字列に「?」が含まれる時、「?」より前にある文字列だけがエンコードされます。

VB.NET
コードを隠すコードを選択
Dim str As String = "http://localhost/<文字> /f.cgi?w=文字"

Console.WriteLine(System.Web.HttpUtility.UrlPathEncode(str))
'「http://localhost/<%e6%96%87%e5%ad%97>%20/f.cgi?w=文字」と表示される
C#
コードを隠すコードを選択
string str = "http://localhost/<文字> /f.cgi?w=文字";

Console.WriteLine(System.Web.HttpUtility.UrlPathEncode(str));
//「http://localhost/<%e6%96%87%e5%ad%97>%20/f.cgi?w=文字」と表示される

HttpUtility.UrlEncodeUnicodeメソッドは、Unicode文字列("%u"で始まる4桁の16進数)にエンコードします。しかしこのメソッドは.NET Framework 4.5からObsolete属性が適用され、使うべきではないとされました。

VB.NET
コードを隠すコードを選択
Dim str As String = "あいうえお- &!"

Console.WriteLine(System.Web.HttpUtility.UrlEncodeUnicode(str))
'「%u3042%u3044%u3046%u3048%u304a-+%26!」と表示される
C#
コードを隠すコードを選択
string str = "あいうえお- &!";

Console.WriteLine(System.Web.HttpUtility.UrlEncodeUnicode(str));
//「%u3042%u3044%u3046%u3048%u304a-+%26!」と表示される

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

  • 「???を参照に追加します」の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。