이스케이프 된 유니 코드로 문자열을 어떻게 디코딩합니까?


89

이름이 무엇인지 잘 모르기 때문에 검색하는 데 문제가 있습니다. 어떻게에서 유니 코드 문자열을 디코딩 할 수 http\u00253A\u00252F\u00252Fexample.comhttp://example.com자바 스크립트로? 나는 노력 unescape, decodeURI그리고 decodeURIComponent그래서 남은 건 오직 문자열 교체 것 같다.

편집 : 문자열이 입력되지 않고 다른 코드의 부분 문자열입니다. 따라서 문제를 해결하려면 다음과 같이 시작해야합니다.

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

이것이 unescape ()가 작동하지 않는 이유를 보여주기를 바랍니다.


문자열은 어디에서 왔습니까?
Cameron

@Cameron : 문자열은 innerHTML을 호출 한 스크립트에서 가져 왔습니다. 이것이 alex의 대답이 작동하지 않는 이유입니다.
styfle

답변:


109

수정 (2017-10-12) :

@MechaLynx 및 @ Kevin-Weber unescape()는 브라우저가 아닌 환경에서 더 이상 사용되지 않으며 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으로 만들까요?
styfle 2012

1
이것은 fromCharCode접근 방식 보다 훨씬 더 빠른 것으로 보입니다
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

116

업데이트 : 이것은 이전 브라우저 또는 비 브라우저 플랫폼에 적용해야하는 솔루션이며 교육 목적으로 유지됩니다. 최신 답변은 아래 @radicand의 답변을 참조하십시오.


이것은 유니 코드, 이스케이프 된 문자열입니다. 먼저 문자열이 이스케이프 된 다음 유니 코드로 인코딩되었습니다. 다시 정상으로 변환하려면 :

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함수를 사용하여 문자열을 적절한 형식으로 디코딩합니다.


3
감사. 당신이하는 일에 대해 조금 설명해 주시겠습니까? 정규식이 \u접두어와 4 자 16 진수 (문자 또는 숫자)를 찾는 것 같습니다 . replace 메서드의 기능은 어떻게 작동합니까?
styfle 2011 년

1
당신 말이 맞아요, 설명이 필요해서 제 글을 업데이트했습니다. 즐겨!
Ioannis Karadimas

1
훌륭한 솔루션. 제 경우에는 서버에서 전송되는 모든 국제 (비 ASCII) 문자를 이스케이프 된 유니 코드로 인코딩 한 다음 브라우저에서 함수를 사용하여 문자를 올바른 UTF-8 문자로 디코딩합니다. 모든 언어 (즉, 태국어)에서 문자를 포착하기 위해 다음 정규식을 업데이트해야한다는 것을 알았습니다.var r = /\\u([\d\w]{1,})/gi;
Nathan Hanna

2
이것은 JSON.parse접근 방식 보다 상당히 느린 것으로 보입니다
nrabinowitz

1
@IoannisKaradimas 확실히 자바 스크립트에서 폐기와 같은 것이 있습니다. 이를 주장하고 이전 브라우저가 항상 지원되어야한다고 말함으로써이를 지원하는 것은 완전히 비 역사적 관점입니다. 어쨌든 이것을 사용하고 싶고 피하고 싶은 사람은 대신 unescape()사용할 수 있습니다 decodeURIComponent(). 이 경우 동일하게 작동합니다. 그러나 동일한 결과로 지원되고 실행하는 것이 더 빠르기 때문에 radicand의 접근 방식을 권장합니다 (그러나 주석을 읽으십시오).
mechalynx

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

나는 이것을 기존 답변에 대한 주석 아래에 넣을 충분한 담당자가 없습니다.

unescape대부분의 사람들의 요구에 해당하는 URI (또는 인코딩 된 utf-8) 작업에만 사용되지 않습니다. encodeURIComponentjs 문자열을 이스케이프 된 UTF-8로 변환하고 decodeURIComponent이스케이프 된 UTF-8 바이트에서만 작동합니다. decodeURIComponent('%a9'); // error확장 ASCII가 유효한 utf-8이 아니기 때문에 오류가 발생합니다 (아직 유니 코드 값 임에도 불구하고).unescape('%a9'); // © decodeURIComponent를 사용할 때 데이터를 알아야합니다.

decodeURIComponent는 대리자의 일부를 나타내는 utf-8에서 작동 하기 때문에 "%C2"또는 어떤 외로운 바이트 에서 작동하지 않습니다 0x7f. 그러나 decodeURIComponent("%C2%A9") //gives you ©Unescape는 제대로 작동하지 // ©않으며 오류가 발생하지 않으므로 데이터를 모르는 경우 unescape는 버그가있는 코드로 이어질 수 있습니다.


1

이를 JSON.decode위해 사용하면 알아야 할 중요한 단점이 있습니다.

  • 문자열을 큰 따옴표로 묶어야합니다.
  • 많은 문자가 지원되지 않으며 스스로 이스케이프해야합니다. 예를 들어,에 다음 중 하나를 통과 JSON.decode(따옴표에 그들을 배치 후 것은)이 모두 유효하더라도 오류가 발생하지 : \\n, \n, \\0,a"a
  • 16 진수 이스케이프를 지원하지 않습니다. \\x45
  • 유니 코드 코드 포인트 시퀀스를 지원하지 않습니다. \\u{045}

다른주의 사항도 있습니다. 기본적 JSON.decode으로 이러한 목적으로 사용하는 것은 해킹이며 항상 예상하는 방식으로 작동하지 않습니다. JSON문자열 작업이 아니라 라이브러리를 사용하여 JSON을 처리 해야 합니다.


나는 최근에이 문제를 직접 겪었고 강력한 디코더를 원했기 때문에 결국 직접 작성했습니다. 완전하고 철저하게 테스트되었으며 여기에서 사용할 수 있습니다 : https://github.com/iansan5653/unraw . 가능한 한 JavaScript 표준을 모방합니다.

설명:

소스는 약 250 줄이므로 여기에 모두 포함하지는 않지만 기본적으로 다음 Regex를 사용하여 모든 이스케이프 시퀀스를 찾은 다음 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.