Кодировка substr_replace в PHP

Я хочу записать в текстовый файл. Когда я использую substr_replace() в PHP кодировка меняется. Он неправильно печатает греческие символы. Если я этого не сделаю, все в порядке. Как я могу это исправить?

<?php
    $file = "test.txt";
    $writeFile = fopen($file, "w+"); // Read/write
    $myarray = array("δφδφ", "δφδσφδσ", "δφδφδ");
    $myarray[0] = substr_replace($myarray[0], "ε", 0, 1);

    foreach ($myarray as $data) {
        fwrite($writeFile, $data . "\n");
    }
?>

Исход

ε�φδφ
δφδσφδσ
δφδφδ

Результат без каких-либо substr_replace()

δφδφ
δφδσφδσ
δφδφδ


person Community    schedule 28.06.2012    source источник
comment
Вы можете попробовать эту многобайтовую функцию lv.php.net/manual/ ru/function.substr-replace.php#59544   -  person arma    schedule 28.06.2012
comment
Вы должны использовать многобайтовые функции, чтобы делать то, что вы хотите в этом случае. Обычный substr_replace работает только с данными в виде двоичной строки, не заботясь о кодировке.   -  person Christian    schedule 28.06.2012


Ответы (4)


Вы можете использовать эти две функции:

Из shkspr. моби:

function mb_substr_replace($original, $replacement, $position, $length)
{
    $startString = mb_substr($original, 0, $position, "UTF-8");
    $endString = mb_substr($original, $position + $length, mb_strlen($original), "UTF-8");

    $out = $startString . $replacement . $endString;

    return $out;
}

Из GitHub:

function mb_substr_replace($str, $repl, $start, $length = null)
{
    preg_match_all('/./us', $str, $ar);
    preg_match_all('/./us', $repl, $rar);
    $length = is_int($length) ? $length : utf8_strlen($str);
    array_splice($ar[0], $start, $length, $rar[0]);
    return implode($ar[0]);
}

Я пробовал оба, и оба работают хорошо.

person Mohammad Kermani    schedule 25.02.2016

Предполагая, что вы кодируете греческий язык в многобайтовой кодировке (например, UTF-8), это не сработает, потому что основные строковые функции PHP, включая substr_replace, не поддерживают многобайтность. Они рассматривают один символ как равный одному байту, а это означает, что вы в конечном итоге разрежете многобайтовые символы пополам, если замените только их первый байт. Вам нужно использовать более ручной подход с использованием многобайтовой строковой функции, такой как mb_substr:

mb_internal_encoding('UTF-8');
echo 'ε' . mb_substr('δφδφ', 1);

Комментарий, на который @arma ссылается в комментариях, включает эту функциональность в функция.

person deceze♦    schedule 28.06.2012

Попробуйте эту версию:

function mb_substr_replace ($string, $replacement, $start, $length = 0) 
{
    if (is_array($string)) 
    {
        foreach ($string as $i => $val)
        {
            $repl = is_array ($replacement) ? $replacement[$i] : $replacement;
            $st   = is_array ($start) ? $start[$i] : $start;
            $len  = is_array ($length) ? $length[$i] : $length;

            $string[$i] = mb_substr_replace ($val, $repl, $st, $len);
        }

        return $string;
    }

    $result  = mb_substr ($string, 0, $start, 'UTF-8');
    $result .= $replacement;

    if ($length > 0) {
        $result .= mb_substr ($string, ($start+$length+1), mb_strlen($string, 'UTF-8'), 'UTF-8');
    }

    return $result;
}
person Edson Medina    schedule 08.11.2012
comment
эта функция глючит - person evilReiko; 26.01.2014
comment
Хотите объяснить @evilReiko? - person Edson Medina; 27.01.2014
comment
Пробовал, работало нормально, но потом заметил, что иногда убирает первый символ после замены - person evilReiko; 27.01.2014
comment
@evilReiko Первый символ $replacement? - person Edson Medina; 28.01.2014
comment
Я так думаю (прошло несколько дней с тех пор, как я в последний раз пробовал эту функцию) - person evilReiko; 28.01.2014
comment
Читал в комментариях, что эта функция глючит. Это правильно? Вы пробовали @EdsonMedina? - person Mohammad Kermani; 25.02.2016

Вы можете попробовать использовать функцию mb_convert_encoding(), чтобы установить правильную кодировку.

person user1474090    schedule 28.06.2012