<?xml version="1.0" encoding="utf-8"?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
<description>
<title-info>
<genre>sf_history</genre>
<author><first-name>Имя автора</first-name><last-name>Фамилия автора</last-name></author>
<book-title>Регулярные выражения для обработки строк UTF-8 в P</book-title>
<date>Дата</date>
<lang>ru</lang>
</title-info>
<document-info>
<author><nickname></nickname></author>
<program-used>Lib converter jcms</program-used>
<id></id>
<version>1.0</version>
</document-info>
</description>
<body><title><p>Регулярные выражения для обработки строк UTF-8 в P</p></title>
<section><p>При разработке многоязычных сайтов для HTML-страниц наиболее удобней и предпочтительней использовать кодировку UTF-8, обеспечивающую поддержку всех или почти всех существующих языков и кодирующую ASCII-символы (латинский алфавит, цифры и специальные символы) одним байтом, а национальные алфавиты — несколькими. Таким образом, кодировка UTF-8 имеет переменную физическую длину каждого символа. В связи с этим иногда возникают проблемы при программировании мультиязычных сайтов.</p>
<p>К примеру, в языке программирования PHP функции strlen и substr выдают некорректные результаты, если в строке имеются символы национального алфавита (поскольку предназначены для работы с однобайтовой кодировкой). Конечно же, в PHP существуют такие функции как mb_strlen и mb_susbtr, специально предназначенные для работы с мультибайтовыми строками. Но, по умолчанию поддержка Multibyte String Functions в PHP выключена, что автоматически ограничивает выбор хостинга для проектируемого сайта. Кроме того, при подключении модуля mb_string указывается набор поддерживаемых языков. А потому существует вероятность, что требуемого Вам языка может не оказаться в списке поддерживаемых.</p>
<p>Впрочем, существует другое, более удобное и гибкое решение проблемы. Воспользовавшись функциями PCRE, корректно воспринимающими кодировку UTF-8, можно написать свои функции utf8_strlen и utf8_substr:</p>
<p>function utf8_strlen($s)</p>
<p>{</p>
<p>return preg_match_all('/./u', $s, $tmp);</p>
<p>}</p>
<p>function utf8_substr($s, $offset, $len = 'all')</p>
<p>{</p>
<p>if ($offset&lt;0) $offset = utf8_strlen($s) + $offset;</p>
<p>if ($len!='all')</p>
<p>{</p>
<p>if ($len&lt;0) $len = utf8_strlen($s) - $offset + $len;</p>
<p>$xlen = utf8_strlen($s) - $offset;</p>
<p>$len = ($len&gt;$xlen) ? $xlen : $len;</p>
<p>preg_match('/^.{' . $offset . '}(.{0,'.$len.'})/us', $s, $tmp);</p>
<p>}</p>
<p>else</p>
<p>{</p>
<p>preg_match('/^.{' . $offset . '}(.*)/us', $s, $tmp);</p>
<p>}</p>
<p>return (isset($tmp[1])) ? $tmp[1] : false;</p>
<p>}</p>
<p>Продолжая тему работы со строками в кодировке UTF-8, рассмотрим еще несколько функций, работающих без установленного в PHP расширения Multibyte String Functions, а именно utf8_strpos и utf8_substr_count:</p>
<p>function utf8_strpos($haystack, $needle, $offset = 0)</p>
<p>{</p>
<p># get substring (if isset offset param)</p>
<p>$offset = ($offset&lt;0) ? 0 : $offset;</p>
<p>if ($offset&gt;0)</p>
<p>{</p>
<p>preg_match('/^.{' . $offset . '}(.*)/us', $haystack, $dummy);</p>
<p>$haystack = (isset($dummy[1])) ? $dummy[1] : '';</p>
<p>}</p>
<p># get relative pos</p>
<p>$p = strpos($haystack, $needle);</p>
<p>if ($haystack=='' or $p===false) return false;</p>
<p>$r = $offset;</p>
<p>$i = 0;</p>
<p># calc real pos</p>
<p>while($i&lt;$p)</p>
<p>{</p>
<p>if (ord($haystack[$i])&lt;128)</p>
<p>{</p>
<p># ascii symbol</p>
<p>$i = $i + 1;</p>
<p>}</p>
<p>else</p>
<p>{</p>
<p># non-ascii symbol with variable length</p>
<p># (handling first byte)</p>
<p>$bvalue = decbin(ord($haystack[$i]));</p>
<p>$i = $i + strlen(preg_replace('/^(1+)(.+)$/', '\1', $bvalue));</p>
<p>}</p>
<p>$r++;</p>
<p>}</p>
<p>return $r;</p>
<p>}</p>
<p>function utf8_substr_count($h, $n)</p>
<p>{</p>
<p># preparing $n for using in reg. ex.</p>
<p>$n = preg_quote($n, '/');</p>
<p># select all matches</p>
<p>preg_match_all('/' . $n . '/u', $h, $dummy);</p>
<p>return count($dummy[0]);</p>
<p>}</p>
</section>
</body>
</FictionBook>