web-dev-qa-db-ja.com

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

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

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

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

Unescape()が機能しない理由を示すことを願っています。

74
styfle

元の回答:

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

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

編集(2017-10-12)

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

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

UPDATE:これは、古いブラウザまたはブラウザ以外のプラットフォームに適用する必要があるソリューションであり、説明のために維持されていることに注意してください。最新の回答については、以下の@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関数を使用して文字列を適切な形式にデコードします。

105

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

Radicandの回答と以下のコメントセクションに基づいて、更新されたソリューションを次に示します。

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

http://example.com

15
Kevin Weber

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

unescapeは、URI(またはエンコードされたutf-8)を扱う場合にのみ非推奨です。これはおそらくほとんどの人のニーズに当てはまります。 encodeURIComponentはjs文字列をエスケープされたUTF-8に変換し、decodeURIComponentはエスケープされたUTF-8バイトでのみ機能します。拡張ASCIIは有効なutf-8ではないため(これはまだUnicode値ですが)、decodeURIComponent('%a9'); // errorのように、unescape('%a9'); // ©のようなエラーが発生します。

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

2
aamarks

このページをご覧ください: http://www.rishida.net/tools/conversion/

コードを上部のテキストボックスに貼り付けます(最初に二重スラッシュを削除します)。

コードはオープンソースです: http://www.rishida.net/tools/conversion/conversionfunctions.js

2
Petah

このためにJSON.decodeを使用すると、次の重要な欠点があります。

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

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


私は最近この問題に自分自身で遭遇し、堅牢なデコーダーを望んでいたので、自分で1つを書くことになりました。完全で完全にテストされており、こちらから入手できます: https://github.com/iansan5653/unraw 。 JavaScriptの標準を可能な限り模倣します。

説明:

ソースは約250行なので、ここにすべてを含めることはしませんが、基本的に次の正規表現を使用してすべてのエスケープシーケンスを検索し、parseInt(string, 16)を使用して解析してbase-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!!' will error])。

/
\\ # 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
0
Ian