regex (in PHP) per abbinare & amp; che non sono entità HTML
Domanda
Ecco l'obiettivo: sostituire tutte le e commerciali standalone con & amp; amp; ma NON sostituire quelli che fanno già parte di un'entità HTML come & amp; nbsp ;.
Penso di aver bisogno di un'espressione regolare per PHP (preferibilmente per le funzioni preg_) che corrisponderà solo alle e commerciali standalone. Semplicemente non so come farlo con preg_replace.
Soluzione
Potresti sempre eseguire html_entity_decode
prima di eseguire htmlentities
? Funziona a meno che tu non voglia fare solo e commerciali (e anche allora puoi giocare con i parametri charset).
Molto più facile e veloce di una regex.
Altri suggerimenti
Il htmlentities ()
di PHP ha l'argomento double_encode
per questo.
Se vuoi fare cose del genere in espressioni regolari, le affermazioni negative diventano utili:
preg_replace('/&(?![a-z#]+;)/i','&',$txt);
Ross mi ha portato a una buona risposta. Ecco il codice che sembra funzionare abbastanza bene. Finora. :-) L'obiettivo, ancora una volta, è convertire HTML in XML, in particolare le descrizioni per i feed RSS. Nel breve test che ho fatto finora (con alcuni dati abbastanza eccentrici) sono stato in grado di prendere stringhe avvolte in CDATA e scartarle. Supera i test di validazione. Grazie, Ross.
//decode all entities
$string=html_entity_decode($string,ENT_COMPAT,'UTF-8');
//entity-encode only &<> and double quotes
$string=htmlspecialchars($string,ENT_COMPAT,'UTF-8');
Gli altri sono buoni suggerimenti e potrebbero essere il modo migliore per farlo. Ma ho pensato di provare a rispondere alla domanda come chiesto, se non altro per fornire un esempio regex.
La seguente è la speciale forma esplosa consentita in alcuni motori. Naturalmente la cosa strana è che un motore che consente regex commentate consente altre espressioni semplificate, ma non così generico. Metterò quelle espressioni semplificate tra parentesi nei commenti.
& # an ampersand
( \# # a '#' character
[1-9] # followed by a non-zero digit,
[0-9]{1,3} # with between 2 and 4 (\d{1,3} or \p{IsDigit}{1,3})
| [A-Za-z] # OR a letter (\p{IsAlpha})
[0-9A-Za-z]+ # followed by letters or numbers (\p{IsAlnum}+)
)
; # all capped with a ';'
Potresti anche lanciare un mucchio di entità previste anche lì, per aiutare lo scanner regex.
& # an ampersand
( amp | apos | gt | lt | nbsp | quot
# standard entities
| bull | hellip | [lr][ds]quo | [mn]dash | permil
# some fancier ones
| \# # a '#' character
[1-9] # followed by a non-zero digit,
[0-9]{1,3} # with between 2 and 4
| [A-Za-z] # OR a letter
[0-9A-Za-z]+ # followed by letters or numbers
)
; # all capped with a ';'
Ho avuto lo stesso problema, originariamente utilizzavo:
$string = htmlspecialchars($string, ENT_QUOTES, "UTF-8", FALSE);
Ma serviva che funzionasse con PHP4 e un mix di CharSet, finito con:
function htmlspecialchars_custom($string)
{
$string = str_replace("\x05\x06", "", $string);
$string = preg_replace("/&([a-z\d]{2,7}|#\d{2,5});/i", "\x05\x06$1", $string);
$string = htmlspecialchars($string, ENT_QUOTES);
$string = str_replace("\x05\x06", "&", $string);
return $string;
}
Non è perfetto, ma abbastanza buono per le mie esigenze.