substr může uříznout polovinu znaku
Možná se vám již stalo, že po oříznutí textu php funkcí substr, zobrazil nějaký "ošklivý" znak nebo otazník. Čím to je a jak to vyřešit?
pozn. přišel jsem na to sám, takže se zde mohou vyskytovat faktické nepřesnosti :)
Tak v čem je problém
Do situace, kdy místo prvního nebo posledního znaku v textu oříznutého funkcí substr uvidíte jen otazník, se můžete dostat pouze v případě, že používáte více jak osmi bitovou znakovou sadu. Takže pokud používáte například ISO8859-2 nebo Windows-1250, tak se do tohoto problému nedostanete. Problém nastává, jestliže používáte velmi častou sadu UTF-8. To sice základní znaky ukládá do osmi bitů, ale pokud napíšete nějaký např. český znak, tak se musí uložit do 16 bitů, neboli dvou bajtů. Ptáte se jak to souvisí s našim problémem?
Funkce substr neořezává řetězec - jak by se na první pohled zdálo - podle znaků, ale podle bajtů. Pokud chceme například slovo "něco" oříznout na 3 znaky bajty, tak v případě použité znakové sady UTF-8 dostaneme pouze "ně", protože znak "ě" se musí uložit do dvou bajtů. V případě ISO8859-2 pak dostaneme "něc", protože zde se znak "ě" vejde do jednoho bajtu. Větší problém je, když stejný řetězec chceme oříznout na 2 znaky. To se nám zobrazí pouze "n�" - což zrovna pěkné neni.
Jak to vyřešit
Při řešení tohoto pro mě napadlo zdrojový text převést do ISO8859-2, takže všechny znaky nyní budou mít pouze 1 bajt. Potom zkrátit funkcí substr a nakonec zase vrátit do UTF-8.
<?
$text="Nějaký ukázkový text";
echo iconv("iso8859-2", "utf-8", substr(iconv("utf-8", "iso8859-2", $text),0,10));
?>
Při použití tohoto kódu dostaneme Nějaký uká. Pokud bychom použili jen samotné substr, vrátilo by se nám pouze Nějaký u
Update: proč to dělat jednoduše, když to jde složitě? Pro tento problém je zde stvořená funkce mb_substr :)