При разработке многоязычных сайтов для HTML-страниц наиболее удобней и предпочтительней использовать кодировку UTF-8, обеспечивающую поддержку всех или почти всех существующих языков и кодирующую ASCII-символы (латинский алфавит, цифры и специальные символы) одним байтом, а национальные алфавиты — несколькими. Таким образом, кодировка UTF-8 имеет переменную физическую длину каждого символа. В связи с этим иногда возникают проблемы при программировании мультиязычных сайтов. К примеру, в языке программирования PHP функции strlen и substr выдают некорректные результаты, если в строке имеются символы национального алфавита (поскольку предназначены для работы с однобайтовой кодировкой). Конечно же, в PHP существуют такие функции как mb_strlen и mb_susbtr, специально предназначенные для работы с мультибайтовыми строками. Но, по умолчанию поддержка Multibyte String Functions в PHP выключена, что автоматически ограничивает выбор хостинга для проектируемого сайта. Кроме того, при подключении модуля mb_string указывается набор поддерживаемых языков. А потому существует вероятность, что требуемого Вам языка может не оказаться в списке поддерживаемых. Впрочем, существует другое, более удобное и гибкое решение проблемы. Воспользовавшись функциями PCRE, корректно воспринимающими кодировку UTF-8, можно написать свои функции utf8_strlen и utf8_substr: function utf8_strlen($s) { return preg_match_all('/./u', $s, $tmp); } function utf8_substr($s, $offset, $len = 'all') { if ($offset<0) $offset = utf8_strlen($s) + $offset; if ($len!='all') { if ($len<0) $len = utf8_strlen($s) - $offset + $len; $xlen = utf8_strlen($s) - $offset; $len = ($len>$xlen) ? $xlen : $len; preg_match('/^.{' . $offset . '}(.{0,'.$len.'})/us', $s, $tmp); } else { preg_match('/^.{' . $offset . '}(.*)/us', $s, $tmp); } return (isset($tmp[1])) ? $tmp[1] : false; } Продолжая тему работы со строками в кодировке UTF-8, рассмотрим еще несколько функций, работающих без установленного в PHP расширения Multibyte String Functions, а именно utf8_strpos и utf8_substr_count: function utf8_strpos($haystack, $needle, $offset = 0) { # get substring (if isset offset param) $offset = ($offset<0) ? 0 : $offset; if ($offset>0) { preg_match('/^.{' . $offset . '}(.*)/us', $haystack, $dummy); $haystack = (isset($dummy[1])) ? $dummy[1] : ''; } # get relative pos $p = strpos($haystack, $needle); if ($haystack=='' or $p===false) return false; $r = $offset; $i = 0; # calc real pos while($i<$p) { if (ord($haystack[$i])<128) { # ascii symbol $i = $i + 1; } else { # non-ascii symbol with variable length # (handling first byte) $bvalue = decbin(ord($haystack[$i])); $i = $i + strlen(preg_replace('/^(1+)(.+)$/', '\1', $bvalue)); } $r++; } return $r; } function utf8_substr_count($h, $n) { # preparing $n for using in reg. ex. $n = preg_quote($n, '/'); # select all matches preg_match_all('/' . $n . '/u', $h, $dummy); return count($dummy[0]); }
|