[javascript] 디코딩 & amp; JavaScript로 돌아 가기

나는 같은 문자열을 가지고

var str = 'One & two & three';

웹 서버에 의해 HTML로 렌더링됩니다. 그 문자열을

'One & two & three'

현재, 내가하고있는 일입니다 (jQuery의 도움으로).

$(document.createElement('div')).html('{{ driver.person.name }}').text()

그러나 나는 내가 잘못하고 있다는 불안감을 느낍니다. 나는 시도했다

unescape("&")

그러나 그것은 작동하지 않는 것 같습니다, decodeURI / decodeURIComponent도 마찬가지입니다.

다른 기본적이고 우아한 방법이 있습니까?



답변

JavaScript에서 HTML (텍스트 및 기타)을 해석하기위한보다 현대적인 옵션은 DOMParserAPI 의 HTML 지원입니다 ( 여기서는 MDN 참조 ). 따라서 브라우저의 기본 HTML 파서를 사용하여 문자열을 HTML 문서로 변환 할 수 있습니다. 2014 년 말부터 모든 주요 브라우저의 새 버전에서 지원되었습니다.

텍스트 내용 만 해독하려면 문서 본문에 유일한 내용으로 넣고 문서를 구문 분석 한 다음을 꺼낼 수 있습니다 .body.textContent.

var encodedStr = 'hello & world';

var parser = new DOMParser;
var dom = parser.parseFromString(
    '<!doctype html><body>' + encodedStr,
    'text/html');
var decodedString = dom.body.textContent;

console.log(decodedString);

우리는 볼 수 에 대한 초안 사양DOMParser 자바 스크립트 구문 분석 된 문서를 사용할 수 없습니다 우리가 보안 문제없이이 텍스트 변환을 수행 할 수 있습니다.

parseFromString(str, type)방법에 따라 다음 단계를 실행해야합니다 유형 :

  • "text/html"

    str 을 구문 분석 HTML parser하고 새로 작성된을 리턴하십시오 Document.

    스크립팅 플래그는 “disabled”로 설정해야합니다.

    노트

    script요소는 실행 불가능으로 표시되고 컨텐츠는 noscript마크 업으로 구문 분석됩니다.

그것은이 질문의 범위를 넘어,하지만 참고하시기 바랍니다 당신은 구문 분석 DOM 노드 자체 (뿐만 아니라 자신의 텍스트 내용)을 복용하고 라이브 문서 DOM로 이동하는 경우, 그것은 그들의 스크립트가 다시 활성화 될 가능성이 있다고, 거기 수 보안 문제가됩니다. 나는 그것을 연구하지 않았으므로주의하십시오.


답변

모든 인코딩 된 HTML 엔터티 또는 그 &amp;자체 를 디코딩해야 합니까?

처리 해야하는 경우 &amp;다음을 수행 할 수 있습니다.

var decoded = encoded.replace(/&amp;/g, '&');

모든 HTML 엔티티를 디코딩 해야하는 경우 jQuery없이 수행 할 수 있습니다.

var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;

이 답변의 이전 버전에서 보안 허점을 강조하고 아래 에서 잠재적 XSS 취약성을 완화 textarea하기보다는 사용 하는 것이 좋습니다 div. 이러한 취약점은 jQuery를 사용하든 일반 JavaScript를 사용하든 존재합니다.


답변

Matthias Bynens는이를위한 라이브러리를 가지고 있습니다 : https://github.com/mathiasbynens/he

예:

console.log(
    he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro ")
);
// Logs "Jörg & Jürgen rocked to & fro"

요소의 HTML 내용을 설정하고 텍스트 내용을 다시 읽는 것과 관련된 해킹보다 선호하는 것이 좋습니다. 이러한 접근 방식은 작동 할 수 있지만 신뢰할 수없는 사용자 입력에 사용되는 경우 믿을 수 없을 정도로 위험하며 XSS 기회를 제공합니다.

실제로 라이브러리에로드 할 수 없다면 이 답변textarea설명 된 해킹 을 거의 중복되는 질문에 사용할 수 있습니다.

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'

그러나 이와 비슷한 접근 방식에 영향을 미치는 보안 문제에 유의하십시오. 링크 된 답변에 나열되어 있습니다! 이 접근 방식은 해킹이며 앞으로 허용되는 내용 textarea(또는 특정 브라우저의 버그)에 대한 향후 변경으로 인해 언젠가 XSS 취약점이있는 코드에 의존 할 수 있습니다.


답변

var htmlEnDeCode = (function() {
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() {
        charToEntity = {};
        entityToChar = {};
        // add the default set
        addCharacterEntities({
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        });
    }

    function addCharacterEntities(newEntities) {
        var charKeys = [],
            entityKeys = [],
            key, echar;
        for (key in newEntities) {
            echar = newEntities[key];
            entityToChar[key] = echar;
            charToEntity[echar] = key;
            charKeys.push(echar);
            entityKeys.push(key);
        }
        charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
        entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
    }

    function htmlEncode(value){
        var htmlEncodeReplaceFn = function(match, capture) {
            return charToEntity[capture];
        };

        return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
    }

    function htmlDecode(value) {
        var htmlDecodeReplaceFn = function(match, capture) {
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        };

        return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
    }

    resetCharacterEntities();

    return {
        htmlEncode: htmlEncode,
        htmlDecode: htmlDecode
    };
})();

이것은 ExtJS 소스 코드에서 가져온 것입니다.


답변

element.innerText 또한 트릭을 수행합니다.


답변

Lodash unescape / escape 기능을 사용할 수 있습니다 https://lodash.com/docs/4.17.5#unescape

import unescape from 'lodash/unescape';

const str = unescape('fred, barney, &amp; pebbles');

str은 될 것이다 'fred, barney, & pebbles'


답변

나와 같은 것을 찾고있는 경우 멋지고 안전한 JQuery 메소드가 있습니다.

https://api.jquery.com/jquery.parsehtml/

당신은 f.ex 할 수 있습니다. 콘솔에 이것을 입력하십시오 :

var x = "test &amp;";
> undefined
$.parseHTML(x)[0].textContent
> "test &"

따라서 $ .parseHTML (x)는 배열을 반환하며 텍스트 내에 HTML 마크 업이 있으면 array.length는 1보다 큽니다.