Как мне декодировать строку с помощью экранированного юникода?

Я не уверен, как это называется, поэтому у меня проблемы с поиском. Как я могу декодировать строку с Unicode из http\u00253A\u00252F\u00252Fexample.com в http://example.com с JavaScript? Я старался unescape, decodeURI, а также decodeURIComponent так что я думаю, что осталось только заменить строку.

РЕДАКТИРОВАТЬ: строка не печатается, а скорее подстрока из другого фрагмента кода. Итак, чтобы решить проблему, вы должны начать с чего-то вроде этого:

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

Я надеюсь, что это показывает, почему unescape() не работает.

8 ответов

Решение

Оригинальный ответ:

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

Вы можете переложить всю работу на JSON.parse

Изменить (2017-10-12):

@MechaLynx и @ Кевин-Вебер отмечают, что unescape() не рекомендуется использовать в средах без браузера и не существует в TypeScript. decodeURIComponent это замена замены. Для большей совместимости используйте нижеприведенное:

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

ОБНОВЛЕНИЕ: Обратите внимание, что это решение, которое должно применяться к более старым браузерам или не браузерным платформам, и поддерживается в учебных целях. Пожалуйста, обратитесь к ответу @radicand ниже для более актуального ответа.


Это Unicode, экранированная строка. Сначала строка была экранирована, затем закодирована с помощью 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 может принимать функцию, которая будет выполняться для каждого совпадения. Возвращение этой функции заменит само совпадение в строке.

Я использую второй параметр, который принимает эта функция, то есть группу, которую мне нужно использовать, и преобразовываю ее в эквивалентную последовательность utf-8, затем использую встроенный unescape функция для декодирования строки в правильную форму.

Обратите внимание, что использование unescape() устарела и не работает с компилятором TypeScript, например.

Основываясь на ответе radicand и разделе комментариев ниже, вот обновленное решение:

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

http://example.com

С помощью JSON.decode поскольку это имеет существенные недостатки, о которых вы должны знать:

  • Вы должны заключить строку в двойные кавычки
  • Многие символы не поддерживаются, и их необходимо экранировать. Например, передача любого из следующего вJSON.decode (после заключения в двойные кавычки) приведет к ошибке, даже если все они действительны: \\n, \n, \\0, a"a
  • Он не поддерживает шестнадцатеричные escape-последовательности: \\x45
  • Он не поддерживает последовательности кодовых точек Unicode: \\u{045}

Есть и другие предостережения. По сути, используяJSON.decodeдля этой цели это взлом, и он работает не так, как вы всегда ожидали. Вам следует придерживатьсяJSON библиотека для обработки JSON, а не для строковых операций.


Недавно я сам столкнулся с этой проблемой и хотел получить надежный декодер, поэтому в итоге я написал его сам. Он полностью и тщательно протестирован и доступен здесь: https://github.com/iansan5653/unraw. Он максимально приближен к стандарту JavaScript.

Пояснение:

Исходный код составляет около 250 строк, поэтому я не буду включать его здесь, но по сути он использует следующее регулярное выражение для поиска всех escape-последовательностей, а затем анализирует их с помощью 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

Прокомментировано (ПРИМЕЧАНИЕ. Это регулярное выражение соответствует всем escape-последовательностям, включая недопустимые. Если строка выдает ошибку в 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

У меня недостаточно представителя, чтобы добавить это к комментариям к существующим ответам:

unescape не рекомендуется только для работы с URI (или любым кодированным utf-8), что, вероятно, соответствует потребностям большинства людей. encodeURIComponent преобразует строку js в экранированный UTF-8 и decodeURIComponent работает только на экранированных байтах UTF-8. Выдает ошибку для чего-то вроде decodeURIComponent('%a9'); // error потому что расширенный ascii недопустим utf-8 (хотя это все еще значение в юникоде), тогда как unescape('%a9'); // © Поэтому вам нужно знать свои данные при использовании decodeURIComponent.

decodeURIComponent не будет работать на "%C2" или любой одиночный байт 0x7f потому что в utf-8 это указывает на часть суррогата. тем не мение decodeURIComponent("%C2%A9") //gives you © Unescape не будет работать на этом должным образом // © И это не выдаст ошибку, поэтому unescape может привести к ошибочному коду, если вы не знаете свои данные.

Посмотрите на эту страницу: http://www.rishida.net/tools/conversion/

Вставьте ваш код в верхнее текстовое поле (сначала удалите двойную косую черту).

Код с открытым исходным кодом: http://www.rishida.net/tools/conversion/conversionfunctions.js

Это не ответ на этот точный вопрос, но для тех, кто попадает на эту страницу через результат поиска и кто пытается (как я) построить один символ Unicode с учетом последовательности экранированных кодовых точек, обратите внимание, что вы можете передать несколько аргументы String.fromCodePoint() вот так:

      String.fromCodePoint(parseInt("1F469", 16), parseInt("200D", 16), parseInt("1F4BC", 16)) // 👩‍💼

Конечно, вы можете проанализировать свою строку, чтобы извлечь строки шестнадцатеричного кода, а затем сделать что-то вроде:

      String.fromCodePoint(...hexCodePointStrings)

В моем случае я пытался unescape HTML файл что-то вроде

      "\u003Cdiv id=\u0022app\u0022\u003E\r\n    \u003Cdiv data-v-269b6c0d\u003E\r\n        \u003Cdiv data-v-269b6c0d class=\u0022menu\u0022\u003E\r\n    \u003Cdiv data-v-269b6c0d class=\u0022faux_column\u0022\u003E\r\n        \u003Cdiv data-v-269b6c0d class=\u0022row\u0022\u003E\r\n            \u003Cdiv data-v-269b6c0d class=\u0022col-md-12\u0022\u003E\r\n"  

к

      <div id="app">
    <div data-v-269b6c0d>
        <div data-v-269b6c0d class="menu">
    <div data-v-269b6c0d class="faux_column">
        <div data-v-269b6c0d class="row">
            <div data-v-269b6c0d class="col-md-12">

Вот ниже работает в моем случае:

      const jsEscape = (str: string) => {
  return str.replace(new RegExp("'", 'g'),"\\'");
}

export const decodeUnicodeEntities = (data: any) => {
  return unescape(jsEscape(data));
}

// Use it
const data = ".....";
const unescaped = decodeUnicodeEntities(data); // Unescaped html

Другие вопросы по тегам