@BjornBorn

Почему код некорректно работает с кириллицей?

Нужно посчитать процентное содержание каждого символа в тексте.

// исходная строка
$string = 'тестовая строка';

// строка с удаленными пробелами
$string = str_replace(' ', '', $string);

// строка, где удалены все повторяющиеся символы
$uniqueSymbols = implode(array_unique(mb_str_split($string, 1)));

// перебираем строку через цикл for
for ($i = 0; $i < mb_strlen($uniqueSymbols); $i++) {
         // символ строки           формула
    echo $uniqueSymbols[$i] .' - '. round((mb_substr_count($string, $string[$i]) / mb_strlen($string)) * 100, 1) . ' %<br><br>';
}


Если вводить английские символы, то всё работает корректно, но если вводить символы на кириллице, то вместо символов показывает кракозябры, а вместо процентов "0".
  • Вопрос задан
  • 202 просмотра
Решения вопроса 1
pickHabr
@pickHabr
Костыльных дел мастер
Потому что кириллица, когда ты берешь $uniqueSymbols[$i] ты берешь не итую букву, а итый байт

$letter = mb_substr($uniqueSymbols, $i, 1);
echo $letter .' - '. round((mb_substr_count($string, $letter) / mb_strlen($string)) * 100, 1) . ' %<br><br>';
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
ipatiev
@ipatiev Куратор тега PHP
Потомок старинного рода Ипатьевых-Колотитьевых
Неэффективность этого решения просто вопиёт к небу. Перебирать строку столько раз, сколько в ней букв - это же кощунство. Неужели нельзя за один проход посчитать символы, а за второй вывести их веса? И получить условные O(n*3) вместо O(n*3 + n^2).
$len = mb_strlen($string);
$counts = array_count_values(mb_str_split($string));
foreach ($counts as $letter => $count) {
    echo "$letter: " . round($count / $len * 100, 1). "\n";
}

И заодно не придётся выковыривать из строки отдельные символы, которые мы уже выковыряли через mb_str_split.

А для практики будет полезнее реализовать подсчет символов самостоятельно, без использования встроенной функции РНР
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы