2

URI.unescapeを使用し てテキストをエスケープ解除していますが、残念ながら奇妙なエラーが発生します。

 # encoding: utf-8
 require('uri')
 URI.unescape("%C3%9Fą")

結果は

 C:/Ruby193/lib/ruby/1.9.1/uri/common.rb:331:in `gsub': incompatible character encodings: ASCII-8BIT and UTF-8 (Encoding::CompatibilityError)
    from C:/Ruby193/lib/ruby/1.9.1/uri/common.rb:331:in `unescape'
    from C:/Ruby193/lib/ruby/1.9.1/uri/common.rb:649:in `unescape'
    from exe/fail.rb:3:in `<main>'

なぜ?

4

3 に答える 3

9

理由はわかりませんが、次のCGI.unescape方法を使用できます。

# encoding: utf-8
require 'cgi'
CGI.unescape("%C3%9Fą")
于 2012-04-26T06:16:49.517 に答える
5

URI.unescape非ASCII入力の実装は壊れています。1.9.3バージョンは次のようになります。

def unescape(str, escaped = @regexp[:ESCAPED])
  str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(str.encoding)
end

使用中の正規表現はです/%[a-fA-F\d]{2}/。したがって、文字列を調べて、パーセント記号とそれに続く2桁の16進数を探します。ブロック内$&には、一致したテキスト(たとえば、「%C3」)があり$&[1,2]、先頭のパーセント記号('C3')がない一致したテキストになります。次にString#hex、その16進数をFixnum(195)に変換し、配列()でラップして、バイトマングリングを実行[195]できるようにします。Array#pack問題はpack、1つのバイナリバイトが得られることです。

> puts [195].pack('C').encoding
ASCII-8BIT

ASCII-8BITエンコーディングは、「バイナリ」(つまり、特定のエンコーディングを持たないプレーンバイト)とも呼ばれます。次に、ブロックはそのバイトを返し、作業中のUTF-8エンコードされたコピーにString#gsub挿入しようとすると、エラーが発生します。strgsub

互換性のない文字エンコード:ASCII-8BITおよびUTF-8(Encoding :: CompositeError)

(一般的に)バイナリバイトをUTF-8文字列に詰め込むことはできないからです。あなたはしばしばそれで逃げることができます:

URI.unescape("%C3%9F")         # Works
URI.unescape("%C3µ")           # Fails
URI.unescape("µ")              # Works, but nothing to gsub here
URI.unescape("%C3%9Fµ")        # Fails
URI.unescape("%C3%9Fpancakes") # Works

非ASCIIデータをURLエンコードされた文字列に混合し始めると、物事は崩壊し始めます。

簡単な修正の1つは、文字列をデコードする前に文字列をバイナリに切り替えることです。

def unescape(str, escaped = @regexp[:ESCAPED])
  encoding = str.encoding
  str = str.dup.force_encoding('binary')
  str.gsub(escaped) { [$&[1, 2].hex].pack('C') }.force_encoding(encoding)
end

force_encoding別のオプションは、をブロックにプッシュすることです。

def unescape(str, escaped = @regexp[:ESCAPED])
  str.gsub(escaped) { [$&[1, 2].hex].pack('C').force_encoding(encoding) }
end

gsub失敗する場合と成功する場合がある理由はわかりません。

于 2012-04-26T21:17:56.797 に答える
0

使用を提案するVasiliyの答えを拡張するにはCGI.unescape

Ruby 2.5.0以降、URI.unescape廃止されました。

https://ruby-doc.org/stdlib-2.5.0/libdoc/uri/rdoc/URI/Escape.html#method-i-unescapeを参照してください。

"This method is obsolete and should not be used. Instead, use CGI.unescape, URI.decode_www_form or URI.decode_www_form_component depending on your specific use case."

于 2019-03-08T01:27:18.283 に答える