エスケープされたUnicodeで文字列をデコードするにはどうすればよいですか?


89

これが何と呼ばれているのかわからないので、検索に問題があります。JavaScriptを使用してからhttp\u00253A\u00252F\u00252Fexample.comへのUnicodeで文字列をデコードするにはどうすればよいhttp://example.comですか?、、を試したunescapeのでdecodeURIdecodeURIComponent残っているのは文字列の置換だけだと思います。

編集:文字列は入力されませんが、別のコードからの部分文字列です。したがって、問題を解決するには、次のようなものから始める必要があります。

var s = 'http\\u00253A\\u00252F\\u00252Fexample.com';

これが、unescape()が機能しない理由を示していると思います。


文字列はどこから来たのですか?
キャメロン

@Cameron:文字列は、取得するためにinnerHTMLを呼び出したスクリプトからのものです。これが、アレックスの答えが機能しない理由です。
スタイフル2011年

回答:


109

編集(2017-10-12)

@MechaLynxおよび@ Kevin-Weberunescape()は、ブラウザ以外の環境では非推奨であり、TypeScriptには存在しないことに注意してください。decodeURIComponentドロップインの代替品です。より広い互換性のために、代わりに以下を使用してください:

decodeURIComponent(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'

元の答え:

unescape(JSON.parse('"http\\u00253A\\u00252F\\u00252Fexample.com"'));
> 'http://example.com'

すべての作業をオフロードできます JSON.parse


6
面白い。私はそれの周りに引用符を追加しなければなりunescape(JSON.parse('"' + s + '"'));ませんでした余分な引用符の理由は何ですか?それはそれを有効なJSONにしますか?
スタイフル2012年

1
これはfromCharCodeアプローチよりも大幅に高速であるように見えることに注意してください:jsperf.com/unicode-func-vs-json-parse
nrabinowitz

17
@styfleの回答に関する重要な注意事項:JSON.parse('"' + s + '"')信頼できないデータの使用を処理する場合は使用しないでください。使用しない、入力に引用符が含まれているときにJSON.parse('"' + s.replace('"', '\\"') + '"')コードが破損します。
ntninja 2014

7
すばらしい答え@ alexander255ですが、実際には次を使用する必要があります:JSON.parse( '"' + str.replace(/ \" / g、 '\\ "' + '"')を使用して、文字列を置き換えるのではなく、文字列
CS

2
これに遭遇し、unescape()廃止されたために心配している人にとっては、この場合decodeURIComponent()と同じようunescape()に機能するので、それをそれに置き換えるだけで問題ありません。
mechalynx 2017年

116

更新:これは古いブラウザまたは非ブラウザプラットフォームに適用する必要があるソリューションであり、教育目的で存続していることに注意してください。最新の回答については、以下の@radicandの回答を参照してください。


これはUnicodeのエスケープされた文字列です。最初に文字列がエスケープされ、次にユニコードでエンコードされました。通常に戻すには:

var x = "http\\u00253A\\u00252F\\u00252Fexample.com";
var r = /\\u([\d\w]{4})/gi;
x = x.replace(r, function (match, grp) {
    return String.fromCharCode(parseInt(grp, 16)); } );
console.log(x);  // http%3A%2F%2Fexample.com
x = unescape(x);
console.log(x);  // http://example.com

説明するために:私は正規表現を使用してを探します\u0025。ただし、置換操作にはこの文字列の一部しか必要ないため、括弧を使用して、再利用する部分を分離し0025ます。この孤立した部分はグループと呼ばれます。

gi式の最後の部分は、最初のインスタンスだけでなく、文字列内のすべてのインスタンスと一致する必要があり、一致では大文字と小文字が区別されないことを示します。例を考えると、これは不要に見えるかもしれませんが、汎用性が追加されます。

ここで、ある文字列から次の文字列に変換するには、各一致の各グループでいくつかの手順を実行する必要がありますが、文字列を変換するだけでは実行できません。便利なことに、String.replace操作は、一致ごとに実行される関数を受け入れることができます。その関数が返されると、文字列内の一致自体が置き換えられます。

この関数が受け入れる2番目のパラメーター(使用する必要のあるグループ)を使用し、それを同等のutf-8シーケンスに変換してから、組み込みunescape関数を使用して文字列を適切な形式にデコードします。


3
ありがとう。あなたがしていることについて少し説明してもらえますか?正規表現が\u4文字の16進数(文字または数字)ではなくプレフィックスを探しているようです。replaceメソッドの関数はどのように機能しますか?
スタイフル2011年

1
あなたは正しいです、それは説明が必要だったので、私は私の投稿を更新しました。楽しい!
ioannis Karadimas 2011年

1
素晴らしいソリューション。私の場合、サーバーから送信されるすべての国際(非ASCII)文字をエスケープされたUnicodeとしてエンコードし、ブラウザーの関数を使用して文字を正しいUTF-8文字にデコードしています。:私は、私はすべての言語(つまり、タイ)からキャッチ文字にするために、次の正規表現を更新するために持っていたことが分かったvar r = /\\u([\d\w]{1,})/gi;
ネイサン・ハンナ

2
これはJSON.parseアプローチよりも大幅に遅いように見えることに注意してください:jsperf.com/unicode-func-vs-json-parse
nrabinowitz

1
@IoannisKaradimasJavascriptの非推奨などは間違いなくあります。それを主張し、古いブラウザを常にサポートする必要があると述べてサポートすることは、完全に歴史的な観点です。いずれにせよ、これを使いたい、そして避けたい人は誰でも代わりにunescape()使うことができますdecodeURIComponent()。この場合も同じように機能します。ただし、radicandのアプローチをお勧めします。これは、サポートされているのと同じくらい簡単で、実行も速く、同じ結果が得られるためです(ただし、コメントを必ず読んでください)。
mechalynx 2017年

21

の使用unescape()非推奨であり、たとえばTypeScriptコンパイラでは機能しないことに注意してください。

radicandの回答と以下のコメントセクションに基づいて、更新されたソリューションは次のとおりです。

var string = "http\\u00253A\\u00252F\\u00252Fexample.com";
decodeURIComponent(JSON.parse('"' + string.replace(/\"/g, '\\"') + '"'));

http://example.com


引用符はJSON文字列を壊し、JSON解析エラーを引き起こす可能性があるため、これは一部の文字列では機能しません。これらの場合、私は他の答え(stackoverflow.com/a/7885499/249327)を使用しました。
nickdos

2

これを既存の回答へのコメントの下に置くのに十分な担当者がいません:

unescapeURI(またはエンコードされたutf-8)を操作する場合にのみ非推奨になります。これは、ほとんどの人のニーズに当てはまる可能性があります。encodeURIComponentjs文字列をエスケープされたUTF-8に変換し、エスケープさdecodeURIComponentれたUTF-8バイトでのみ機能します。decodeURIComponent('%a9'); // error拡張ASCIIが有効なutf-8ではないため(それはまだユニコード値ですが)、エラーをスローしますが、unescape('%a9'); // ©decodeURIComponentを使用するときはデータを知る必要があります。

utf-8ではサロゲートの一部を示し"%C2"ている0x7fため、decodeURIComponentは機能しないか、1バイトオーバーしません。ただし、decodeURIComponent("%C2%A9") //gives you ©Unescapeはその上で適切に機能// ©せず、エラーもスローされないため、データがわからない場合、Unescapeはバグのあるコードにつながる可能性があります。


1

これに使用JSON.decodeすると、次の点に注意する必要がある重大な欠点があります。

  • 文字列は二重引用符で囲む必要があります
  • 多くの文字はサポートされていないため、エスケープする必要があります。たとえば、に次のいずれかを渡すJSON.decode(二重引用符でそれらをラップした後)は、これらはすべて有効であってもエラーになります:\\n\n\\0a"a
  • 16進エスケープはサポートされていません。 \\x45
  • Unicodeコードポイントシーケンスはサポートしていません。 \\u{045}

他にも注意点があります。基本的に、JSON.decodeこの目的での使用はハックであり、常に期待するようには機能しません。JSON文字列操作ではなく、ライブラリを使用してJSONを処理することに固執する必要があります。


私は最近この問題に自分で遭遇し、堅牢なデコーダーが欲しかったので、自分で作成することになりました。完全で徹底的にテストされており、https//github.com/iansan5653/unrawから入手できます。これは、JavaScript標準を可能な限り模倣しています。

説明:

ソースは約250行なので、ここにはすべて含めませんが、基本的には次の正規表現を使用してすべてのエスケープシーケンスを検索し、それらを解析してparseInt(string, 16)16進数をデコードしString.fromCodePoint(number)、対応する文字を取得します。

/\\(?:(\\)|x([\s\S]{0,2})|u(\{[^}]*\}?)|u([\s\S]{4})\\u([^{][\s\S]{0,3})|u([\s\S]{0,4})|([0-3]?[0-7]{1,2})|([\s\S])|$)/g

コメント(注:この正規表現は、無効なものを含むすべてのエスケープシーケンスに一致します。文字列がJSでエラーをスローすると、ライブラリでエラーがスローされます[つまり、'\x!!'エラーが発生します]):

/
\\ # All escape sequences start with a backslash
(?: # Starts a group of 'or' statements
(\\) # If a second backslash is encountered, stop there (it's an escaped slash)
| # or
x([\s\S]{0,2}) # Match valid hexadecimal sequences
| # or
u(\{[^}]*\}?) # Match valid code point sequences
| # or
u([\s\S]{4})\\u([^{][\s\S]{0,3}) # Match surrogate code points which get parsed together
| # or
u([\s\S]{0,4}) # Match non-surrogate Unicode sequences
| # or
([0-3]?[0-7]{1,2}) # Match deprecated octal sequences
| # or
([\s\S]) # Match anything else ('.' doesn't match newlines)
| # or
$ # Match the end of the string
) # End the group of 'or' statements
/g # Match as many instances as there are

そのライブラリの使用:

import unraw from "unraw";

let step1 = unraw('http\\u00253A\\u00252F\\u00252Fexample.com');
// yields "http%3A%2F%2Fexample.com"
// Then you can use decodeURIComponent to further decode it:
let step2 = decodeURIComponent(step1);
// yields http://example.com
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.