2010-05-04 17 views
13

J'essaie de décoder le long trait codé d'une entité numérique en une chaîne, mais il semble que je ne trouve pas une fonction qui puisse le faire correctement. Le meilleur que j'ai trouvé est mb_decode_numericentity(), cependant, pour une raison quelconque, il ne parvient pas à décoder le long tiret et d'autres caractères spéciaux.Comment décoder des entités HTML numériques en PHP

$str = '–'; 

$str = mb_decode_numericentity($str, array(0xFF, 0x2FFFF, 0, 0xFFFF), 'ISO-8859-1'); 

Cela renverra "?".

Quelqu'un sait comment résoudre ce problème?

+3

Un tiret long est-il présent dans l'ISO-8859-1? –

+1

@ColShrapnel: En effet pas. Il est présent dans Windows cp1252, qui est similaire, mais pas ISO-8859-1. Mieux: utilisez UTF-8. – bobince

+1

Certainement, il n'y a pas de long tiret dans ISO/CEI 8859-1 (Latin-1). En fait, c'est un caractère Unicode, et en utilisant UTF-8 aidé. C'était mon erreur que j'ai oublié de changer l'encodage dans le navigateur. Merci à tous! – Yuriy

Répondre

1

mb_decode_numericentity ne gère pas hexadécimal, seulement décimal. Avez-vous le résultat attendu avec:

$str = '–'; 

$str = mb_decode_numericentity ($str , Array(255, 3145727, 0, 65535) , 'ISO-8859-1'); 

Vous pouvez utiliser hexdec pour convertir votre hexadécimal en décimal.

En outre, par curiosité, fait les travaux suivants:

$str = '–'; 

$str = html_entity_decode($str); 
+0

Merci pour une réponse rapide, mais cela retourne '?' ainsi que. – Yuriy

+0

> $ str = html_entity_decode ($ str); C'était la première chose que j'ai essayée. No. – Yuriy

+0

@Yuriy réfutez ou confirmez vos commentaires sur cette ** réponse ** après avoir écrit le commentaire à cette ** question ** au sujet de votre erreur. Je pense que 'html_entity_decode()' est la solution correcte la plus simple. – Apostle

19

L'extrait de code suivant (la plupart du temps volé here et amélioré) fonctionnera pour décimal littéral numérique, et les entités hexa-décimal numériques:

header("content-type: text/html; charset=utf-8"); 

/** 
* Decodes all HTML entities, including numeric and hexadecimal ones. 
* 
* @param mixed $string 
* @return string decoded HTML 
*/ 

function html_entity_decode_numeric($string, $quote_style = ENT_COMPAT, $charset = "utf-8") 
{ 
$string = html_entity_decode($string, $quote_style, $charset); 
$string = preg_replace_callback('~&#x([0-9a-fA-F]+);~i', "chr_utf8_callback", $string); 
$string = preg_replace('~&#([0-9]+);~e', 'chr_utf8("\\1")', $string); 
return $string; 
} 

/** 
* Callback helper 
*/ 

function chr_utf8_callback($matches) 
{ 
    return chr_utf8(hexdec($matches[1])); 
} 

/** 
* Multi-byte chr(): Will turn a numeric argument into a UTF-8 string. 
* 
* @param mixed $num 
* @return string 
*/ 

function chr_utf8($num) 
{ 
if ($num < 128) return chr($num); 
if ($num < 2048) return chr(($num >> 6) + 192) . chr(($num & 63) + 128); 
if ($num < 65536) return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); 
if ($num < 2097152) return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); 
return ''; 
} 


$string ="&#x201D;"; 

echo html_entity_decode_numeric($string); 

Les suggestions d'amélioration sont les bienvenues.

+0

Bien que ' ne soit pas une référence d'entité html valide, il n'est pas rare de "déborder" des documents XML. Ajoutez ce qui suit pour être complètement imperméable à l'eau: '$ string = str_ireplace ('''," '", $ chaîne);' – Tilman

+2

Une autre amélioration: Ce code a une fuite de mémoire terrible. Chaque fois que cela est appelé, une nouvelle fonction lambda créée avec create_function() est bloquée en mémoire. Oui, le manuel sur preg_replace_callback() suggère que la fonction lambda est une "bonne idée" pour rendre le code plus propre. Mais c'est faux. Il n'y a rien de mal à créer une simple fonction réelle 'function chr_utf8_callback ($ matches) { \t return chr_utf8 (hexdec ($ correspond [1])); } 'et en utilisant cela à la place' $ string = preg_replace_callback ('~ & # x ([0-9a-fA-F] +); ~ i', chr_utf8_callback, $ chaîne); – Tilman

+0

@Tilman très bon point, fixe, merci! –