Jak se nenechat vypéct při nahrazování výskytů jednoho řetězce jiným. Search & Replace tricks.
Základní funkcí pro nahrazování řetězců v PHP je str_replace:
$s = "Lorem ipsum";
echo str_replace('ore', 'ide', $s); // vrací "Lidem ipsum"
Díky chytře vymyšlenému kódování UTF-8 ji lze spolehlivě používat
i pro takto kódované řetězce. Navíc jako první dva argumenty lze uvést
pole a funkce potom provede vícenásobné nahrazení. A tady narážíme na
první špíček, který je třeba mít na zřeteli. Každé nahrazení
prochází řetězec znovu, pokud bychom tedy chtěli ve větě
pánské dárky
prohodit dá
<⇒ pá
a získat tak dánské párky
(švédská delikatesa!), žádné
pořadí argumentů k cíli nepovede:
// vrací "dánské dárky"
echo str_replace(array('dá', 'pá'), array('pá', 'dá'), "pánské dárky");
// vrací "pánské párky"
echo str_replace(array('pá', 'dá'), array('dá', 'pá'), "pánské dárky");
Hledanou funkcí, která řetězec projde jen jednou a zamezí vzniku kolizí, je strtr:
// vrací "dánské párky", hurá
echo strtr("pánské dárky", array('pá' => 'dá', 'dá' => 'pá'));
Pokud bychom hledali výskyty podle složitějších pravidel, využijeme
regulární výrazy a funkci preg_replace. Ta také umožňuje
vícenásobné nahrazování a chová se stejně jako str_replace
.
Teď však mířím jinam. Potřebuji v řetězci nahradit všechny čísla
slovem hafo
, což je snadné:
$s = "Radek tvrdí, že má IQ 151. Pěkný sběratelský kousek!";
echo preg_replace('#\d+#', 'hafo', $s);
Zobecněme kód, nechť umí čísla nahradit čímkoliv, co mu předáme
v proměnné $replacement
. Řada programátorů použije:
return preg_replace('#\d+#', $replacement, $s); // spatne!
Což bohužel není dobře. Je třeba si uvědomit, že i v nahrazovaném řetězci mají určité znaky speciální význam (konkrétně lomítko a dolar), proto ho musíme escapovat. Správné obecné řešení je:
return preg_replace('#\d+#', addcslashes($replacement, '$\\'), $s); // ok
Napadají vás ještě nějaké nahrazovací špeky?
Komentáře
BoneFlute #1
Nebyl by vhodnější
preg_quote()
namístoaddcslashes()
? Nebo i v tom je nějaký špek?Jakub Vrána #2
Viz též 5 let starý článek u mě 🙂.
David Grudl #3
#1 BoneFlute, preg_quote použít nelze, escapuje totiž celou řadu dalších znaků kromě těch dvou požadovaných.
BoneFlute #4
#3 David Grudl, Ech, já už to vidím. preg_quote() by se použilo na výraz, který se použije jako regulár, zatímco ty mluvíš o obsahu. Moje chyba.
Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.