Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: JavaScript: HTML-entiteetit normaaliksi tekstiksi

E1ss [17.04.2019 18:00:07]

#

Teen yhtä sovellusta React Nativella ja kohtasin pienen ongelman jota en saa oikein ratkaistuksi. Ajattelin laittaa tänne kysymyksen koska ongelma on varmaan vähän universaalimpi joten monet varmaan osaavat antaa neuvoja. Eli ongelma on kun otan netistä dataa joka tulee sitten esim muodossa "<p>Hello&#8217;s random text&#x2019; more." ja sitten minun pitäisi saada tämä normaaliin muotoon eli muutettua nuo koodit heittomerkeiksi. Luin paljon keskusteluita tästä ja parhaalta keinolta React Nativessa taitaa olla käyttää REgexiä. Eli tässä on koodi jota käytän:

String.prototype.replaceAll = function(search, replacement) {
    var target = this;
    return target.split(search).join(replacement);
};

const fromHTMLtoCorrectFormat = (string) => {
    return string.replaceAll(/&#(\d+);/, function(match, dec) {
        return String.fromCharCode(dec);
    }).replace(/(<([^>]+)>)/ig,"")
}

Ongelma on juuri tuo &#x2019; ja pelkään että joskus kohtaan muitakin ongelmia kun lähden nyt ratkaisemaan tätä tälläisellä keinolla. Mutta ne jotka tuntevan unicode koodeja niin riittääkö tarkastaa vain numerot ja kirjaimet vai voiko olla jotain kummallisuuksia? entä miten tuo ylläoleva kohta korjataan. Yritin /&#(\D+|\d+);/ ja /&#([a-z]+|\d+);/ mutta en saanut toimimaan. Varmaan kuitenkin ratkaisu on joku tämän tapainen.

Metabolix [17.04.2019 19:03:47]

#

Entiteettejä ei voi dekoodata ennen tagien poistoa, koska HTML-koodi voi hajota, jos entiteetti merkitsee esim. >-merkkiä. Entiteetissä #x tarkoittaa heksadesimaalilukua. Käyttämäsi fromCharCode ei toimi yli 65535:n arvoilla. Lisäksi on olemassa paljon tekstimuotoisia entiteettejä (&lt; &gt; &amp; &quot; &apos;).

Tässä on paljon parempi versio koodista:

function getTextFromHTML(html) {
	const entities = {"amp": "&", "lt": "<", "gt": ">", "quot": '"', "apos": "'"};
	return html.replace(
		/(<!--[^]*?-->)|(<[^]*?>)|&#([0-9]+);|&#x([0-9a-fA-F]+);|&([0-9A-Za-z]+);/g,
		function(match, comment, tag, dec, hex, name) {
			if (comment || tag) return "";
			if (dec) return String.fromCodePoint(parseInt(dec, 10));
			if (hex) return String.fromCodePoint(parseInt(hex, 16));
			if (name && entities[name]) return entities[name];
			return match;
		}
	);
}

Entisen koodisi tulos:

alkuperäinen: <a href="&#x22;&#x3e; haista home &#x3c;&#x2f;&#x61;&#x3e;">linkki</a> &#128512;
"dekoodattu": <a href=""> haista home </a>">linkki</a>tagien poisto:  haista home ">linkki 

Oikea tulos:

tagien poisto: linkki &#128512;
dekoodattu: linkki 😀

Edelleen puutteeksi jää, että mm. välejä ei tiivistetä ja rivinvaihdot jäävät tekstiin rivinvaihtoina ja toisaalta esimerkiksi br-tagit eivät tuota rivinvaihtoa. Toisaalta johonkin täytyy laittaa raja.

Muita kysymyksiä vanhasta koodistasi: Miksi erillinen replaceAll-viritelmä? Miksi siellä turha target-muuttuja? Miksi split ja join eikä suoraan oikeaa replacea?

The Alchemist [18.04.2019 06:05:37]

#

Metabolix jätti sanomatta, että natiivi replace toimii jo kuin tämä tyhmä replaceAll-funktio. Ei ole mitään tarvetta kirjoittaa sen kaveriksi omaa funktiota, eikä varsinkaan sellaista jonka suorituskyky on luultavasti aivan järkyttävän huono johtuen tuosta täysin tarpeettomasta string-taulukko-string-muunnoksesta.

Regexeille voi antaa flageja, jotka muuttavat oletusarvoista käyttäytymistä. Lippu g muuttaa replacen korvaamaan jokaisen ilmentymän; /foo/g.

Natiivien luokkien laajentaminen omalla roskalla on myös äärimmäisen huono tapa. Kirjoita ennemmin oma kirjastotyyppinen luokkasi, joka manipuloi parametreina annettuja merkkijonona.

class stringlib {
  static myCustomMethod (string) {
    return string.replace(/foo/g)
  }

  static mySecondCustomThing (string, foo) {
    return string + foo
  }
}

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta