Функция wordwrap() и UTF-8

1.26K
.
dont
Нужно одинаково разделить строку.
Чтоб было понятно, приведу простой пример:
В переменной $test содержится строка, сначала идет кириллица, потом латинский алфавит.
echo wordwrap($test,10,'<br>',true);

Латинский алфавит разделит правильно, по 10 символов, а вот русский по 5. Если поставить нечетную цифру, то вообще может разделить русскую букву на пополам и получится "краказябра"
Вот надо как-то сделать, чтоб строка делилась правильно, независимо от алфавита.
.
вероятно все дело в том что русские символы занимают по 2 байта в то время как английские по 1 байту в кодировке utf-8
--
немного погуглив вот что нашел
function utf8_wordwrap($str, $width, $break, $cut = false) {
    if (!$cut) {
        $regexp = '#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){'.$width.',}\b#U';
    } else {
        $regexp = '#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){'.$width.'}#';
    }
    if (function_exists('mb_strlen')) {
        $str_len = mb_strlen($str,'UTF-8');
    } else {
        $str_len = preg_match_all('/[\x00-\x7F\xC0-\xFD]/', $str, $var_empty);
    }
    $while_what = ceil($str_len / $width);
    $i = 1;
    $return = '';
    while ($i < $while_what) {
        preg_match($regexp, $str,$matches);
        $string = $matches[0];
        $return .= $string.$break;
        $str = substr($str, strlen($string));
        $i++;
    }
    return $return.$str;
}


function utf8_wordwrap($string, $width=75, $break="\n", $cut=false)
 {
   if($cut) {
     // Match anything 1 to $width chars long followed by whitespace or EOS,
     // otherwise match anything $width chars long
     $search = '/(.{1,'.$width.'})(?:\s|$)|(.{'.$width.'})/uS';
     $replace = '$1$2'.$break;
   } else {
     // Anchor the beginning of the pattern with a lookahead
     // to avoid crazy backtracking when words are longer than $width
     $pattern = '/(?=\s)(.{1,'.$width.'})(?:\s|$)/uS';
     $replace = '$1'.$break;
   }
   return preg_replace($search, $replace, $string);
 }


/**
  * Word wrap
  *
  * @param  string  $string
  * @param  integer $width
  * @param  string  $break
  * @param  boolean $cut
  * @param  string  $charset
  * @return string
  */
function iconv_wordwrap($string, $width = 75, $break = "\n", $cut = false, $charset = 'utf-8')
 {
     $stringWidth = iconv_strlen($string, $charset);
     $breakWidth  = iconv_strlen($break, $charset);

     if (strlen($string) === 0) {
         return '';
     } elseif ($breakWidth === null) {
         throw new Zend_Text_Exception('Break string cannot be empty');
     } elseif ($width === 0 && $cut) {
         throw new Zend_Text_Exception('Can\'t force cut when width is zero');
     }

     $result    = '';
     $lastStart = $lastSpace = 0;

     for ($current = 0; $current < $stringWidth; $current++) {
         $char = iconv_substr($string, $current, 1, $charset);

         if ($breakWidth === 1) {
             $possibleBreak = $char;
         } else {
             $possibleBreak = iconv_substr($string, $current, $breakWidth, $charset);
         }

         if ($possibleBreak === $break) {
             $result    .= iconv_substr($string, $lastStart, $current - $lastStart + $breakWidth, $charset);
             $current   += $breakWidth - 1;
             $lastStart  = $lastSpace = $current + 1;
         } elseif ($char === ' ') {
             if ($current - $lastStart >= $width) {
                 $result    .= iconv_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
                 $lastStart  = $current + 1;
             }

             $lastSpace = $current;
         } elseif ($current - $lastStart >= $width && $cut && $lastStart >= $lastSpace) {
             $result    .= iconv_substr($string, $lastStart, $current - $lastStart, $charset) . $break;
             $lastStart  = $lastSpace = $current;
         } elseif ($current - $lastStart >= $width && $lastStart < $lastSpace) {
             $result    .= iconv_substr($string, $lastStart, $lastSpace - $lastStart, $charset) . $break;
             $lastStart  = $lastSpace = $lastSpace + 1;
         }
     }

     if ($lastStart !== $current) {
         $result .= iconv_substr($string, $lastStart, $current - $lastStart, $charset);
     }

     return $result;
 }
.
так же могут возникнуть проблемы и сдругими символами, которые занимают более 1 байта в utf8
.
Screamer, Я пробовал менять кодировку
$test=iconv('utf8','cp1251',$test);

потом делил строку
$test=wordwrap($test,10,'<br>',true);

потом снова менял кодировку и смотрел результат
echo iconv('cp1251','utf8',$test);

Оба алфавита разделились по десять букв. Вообще то мне другое нужно, чтоб строка делилась на равные части с учетом регистра.
Заглавные буквы занимают больше места и кусок с маленькими буквами получается короче.
.
dont, зачем такие извращения? Можно в стиле задать выравнивание по ширине а так я незнаю чем помочь.
.
Screamer, Это не для вывода на экран и тут стилем не помочь. К примеру на картинку наложить длинный текст, чтоб получилась колонка, типа статьи в газете
.
Screamer
dont, аа, ну тут тогда юзай функции для работы с изображениями, там 100% должно быть то что тебе нужно
.
http://php.net/manual/ru/funct ... t.php
http://php.net/manual/ru/funct ... h.php
http://php.net/manual/ru/funct ... x.php
http://php.net/manual/ru/funct ... t.php
.
Screamer, Там кажется не видел такого, чтоб текст можно было делить на на части. Нужно ведь заранее разделить текст на части, а потом накладывать на изображение. Скажу сразу, что размеры изображения не фиксированные.
.
можно попробовать создать пустое изображение с альфа каналом, наложить на него текст, и далее уже его "разрезать" и накладывать на нужное изображение
Всего: 38