Unicode文字をURLエンコードする適切な方法は何ですか?


107

非標準の%uxxxxスキームを知っていますが、このスキームはW3Cによって拒否されているため、賢明な選択とは思えません。

いくつかの興味深い例:

ハートのキャラクター。これをブラウザに入力すると:

http://www.google.com/search?q=♥

次に、コピーして貼り付けます。このURLが表示されます

http://www.google.com/search?q=%E2%99%A5

これにより、Firefox(またはSafari)がこれを実行しているように見えます。

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'

トリプルドット文字のように、Latin-1でエンコードできないものを除いて、これは理にかなっています。

URLを入力すると

http://www.google.com/search?q=…

ブラウザにコピーして貼り付けます

http://www.google.com/search?q=%E2%80%A6

バック。それはやっての結果のようです

urllib.quote_plus(x.encode("utf-8"))

…Latin-1でエンコードできないため、これは理にかなっています。

しかし、ブラウザがUTF-8とLatin-1のどちらでデコードするかをどのように判断するかは、はっきりしていません。

これはあいまいなようですので:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'

動作するので、ブラウザがUTF-8またはLatin-1のいずれでデコードするかをブラウザがどのように判断するのかわかりません。

処理する必要がある特殊文字をどのように処理すればよいですか?


19
どちらの例もUTF-8としてエンコードされています。3バイト長であることを考えると、最初は確かにLatin-1ではありません...
Jakob Borg

2
%E2%99%A5は、UTF-8の「ブラックハートスーツ」のバイト値の16進数です。その黒いハートは、Latin-1文字セットの一部ではありません。
Hawkeye Parker

ブラウザーがエンコードする方法と内容(およびその他の多くの有用な情報)を正確に確認するには、最新のブラウザーに組み込まれている開発者ツールを使用するか、Fiddlerなどの無料のHTTPデバッガーを入手します。
Hawkeye Parker、

回答:


65

私は常にUTF-8でエンコードします。パーセントエンコーディングに関するウィキペディアのページから:

汎用URI構文では、URIの文字データの表現を提供する新しいURIスキームは、実際には、予約なしのセットの文字を変換せずに表し、他のすべての文字をUTF-8に従ってバイトに変換する必要があることを義務付けています。それらの値をパーセントエンコードします。この要件は、RFC 3986の発行とともに2005年1月に導入されました。この日付より前に導入されたURIスキームは影響を受けません。

URLエンコードを行う他の受け入れられた方法が以前あったため、ブラウザーはURIをデコードするいくつかの方法を試みますが、エンコードを行う方法の場合は、UTF-8を使用する必要があります。


8
UTF-8も使用する必要があります。これは、古いURL標準に置き換わる新しいIRI標準(RFC 3987、tools.ietf.org / html / rfc3986)で許可されている唯一のエンコーディングであるためです。
レミールボー・

3
他の人が私と同じくらい驚いた場合、@ RemyLebeauのコメントのテキストはRFC3987について言及していますが、リンクは古い仕様3896へのリンクです。正しいURLは明らかにtools.ietf.org/html/rfc3987
tripleee

うん、ごめんなさい。URIは、RFC 3986によって定義され、IRIは、RFC 3987.によって定義される
レミールボー

10

原則として、ブラウザはフォームの提供元のページのコンテンツタイプに従ってフォームの応答をエンコードするようです。これは、サーバーが「text / xml; charset = iso-8859-1」を送信した場合、同じ形式で応答が返されることを期待していると推測されます。

URLバーにURLを入力するだけの場合、ブラウザには作業するためのベースページがないため、推測する必要があります。したがって、この場合は常にutf-8を実行しているようです(両方の入力で3オクテット形式の値が生成されたため)。

残念なことに、AFAIKでは、クエリ文字列の値を設定する文字、またはURLの文字を解釈するための標準はありません。少なくともクエリ文字列の値の場合、それらが必ずしも文字に対応すると仮定する理由はありません

クエリ文字列がエンコードされると予想される文字セットをサーバーフレームワークに通知する必要があることは既知の問題です。たとえば、Tomcatでは、前に request.setEncoding()(またはいくつかの同様のメソッド)を呼び出す必要があります。 request.getParameter()メソッドのいずれかを呼び出します。このテーマに関するドキュメントの不足は、おそらく多くの開発者の間での問題の認識の欠如を反映しています。(私は定期的にJavaのインタビュー対象者に、ReaderとInputStreamの違いは何であるかを尋ね、定期的に空白に見えます)


6
RFC 3987(tools.ietf.org/html/rfc3986)は標準のエンコードを定義しています。エンコードされていない場合は許可されていない文字をエンコードする場合は、UTF-8を使用する必要があります。
レミールボー・

8

IRI(RFC 3987)は、URI / URL(RFC 3986以前)標準に代わる最新の標準です。URI / URLはUnicodeをネイティブにサポートしていません(まあ、RFC 3986は将来のURI / URLベースのプロトコルをサポートするためのプロビジョニングを追加していますが、過去のRFCを更新していません)。"%uXXXX"スキームは、状況によってはUnicodeを許可する非標準の拡張ですが、誰もが普遍的に実装できるわけではありません。一方、IRIはUnicodeを完全にサポートしており、テキストをUTF-8としてエンコードしてからパーセントエンコードする必要があります。


UnicodeがパーセントエンコーディングだけでなくURLでも完全にサポートされるように、プロトコルの更新を見たいと思います。
Mathieu J.

1
IRIでは、予約文字をエンコードする必要があるいくつかの場合を除いて、エンコードされていないUnicode文字を使用できます。
レミールボー

6

URI(実質的にはASCII)のみが一部のコンテキスト(HTTPを含む)で許可されるため、IRIはURIを置き換えません。

代わりに、IRIを指定すると、ネットワークに出るときにURIに変換されます。


0

最初の質問はあなたのニーズは何ですか?UTF-8エンコーディングは、安価なエディターで作成されたテキストを取得することと、多種多様な言語をサポートすることの間のかなり良い妥協です。エンコードを識別するブラウザーに関しては、(Webサーバーからの)応答がブラウザーにエンコードを通知する必要があります。それでも多くの場合、これが見つからないか間違っているため、ほとんどのブラウザは推測を試みます。彼らは、デフォルトのエンコーディングに適合しない文字があるかどうかを確認するために結果ストリームの一部を読み取ることで推測します。現在、すべてのブラウザ(これはチェックしていませんが、かなりt​​rueに近い)では、デフォルトでutf-8を使用しています。

したがって、他の多くのエンコードスキームの1つを使用するやむを得ない理由がない限り、utf-8を使用してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.