Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Špeky a párky v nahrazování řetězců

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 <⇒ 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

  1. BoneFlute #1

    avatar

    Nebyl by vhodnější preg_quote() namísto addcslashes() ? Nebo i v tom je nějaký špek?

    před 5 lety | reagoval [3] David Grudl
  2. Jakub Vrána http://php.vrana.cz/ #2

    Viz též 5 let starý článek u mě :-).

    před 5 lety
  3. David Grudl http://davidgrudl.com #3

    avatar

    #1 BoneFlute, preg_quote použít nelze, escapuje totiž celou řadu dalších znaků kromě těch dvou požadovaných.

    před 5 lety | reagoval [4] BoneFlute
  4. BoneFlute #4

    avatar

    #3 Davide Grudle, 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.

    před 5 lety

Tento článek byl uzavřen. Už není možné k němu přidávat komentáře.