05.06.2013, 22:24
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
Почему строка "райд" состоит из 8 символов?
Выручайте!
Был сайт на php. Пхп файлы кодировались в Windows-1251, однако в базе данных (MySQL) стояла кодировка UTF-8. При работе с базой приходилось всё время кодировать строки туда-обратно. Решил перекодировать файлы на сервере в UTF-8.
На первый взгляд операция прошла удачно, но стоило мне авторизироваться на своём сайте, как я заметил проблему.
В одном месте ник выводится вертикально следующим образом: implode('<br>', str_split($halfName)). Так вот в этом месте вместо слова Райд пхп вертикально вывел мне в аккурат 8 неизвестных символов (FF отображает их в виде вопросиков).
Входе исследований с помощью FirePHP стало ясно, что длина строк (возвращаемая strlen), состоящих из русских символов, УДВАИВАЕТСЯ , а при применении к этим строкам любых функция (типа str_split или preg_replace) получается абракадабра.
Пожалуйста, помогите решить проблему
|
|
06.06.2013, 18:49
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
Уже 33 просмотра и не одного ответа.
Это такая сложная проблема, такой глупый вопрос или такой длинный пост?
|
|
06.06.2013, 20:04
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Глупый и противный вопрос. Глупый, потому что UTF-8 - 8бит, 2 байта на символ в отличие от c1251, где 1 байт. Глюки связаны с этим. Противный потому что никому не охота разбираться где и в чём проблема конкретно у вас.
__________________
29375, 35
|
|
06.06.2013, 20:25
|
Профессор
|
|
Регистрация: 31.05.2012
Сообщений: 396
|
|
В PHP исходный код представляется в однобайтовой кодировке, и также строки состоят только из символов в однобайтовой кодировке, или байтов.
Каждая буква русского алфавита в UTF-8 представляется двумя байтами, отсюда и данная проблема. Иными словами, strlen показывает количество байтов в строке, и все функции, работающие со строками, работают с отдельными байтами.
Я вижу 2 способа решить эту проблему.
1) Отправить строку на клиент как есть, а уже на клиенте с помощью Джаваскрипта расположить буквы вертикально.
2) Воспользоваться тем, что в UTF-8 первый байт последовательности байтов, представляющей один пункт Юникода, является в пределах 0 - 127 или 196 - 255, а остальные байты не являются. Поэтому на PHP можно написать собственную функцию, вставляющую "<br>" между пунктами Юникода, вместо implode.
|
|
06.06.2013, 20:26
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
Сообщение от Aetae
|
Глупый, потому что UTF-8 - 8бит, 2 байта на символ
|
Вы уж определитесь, 8 бит или всё-таки 2 байта. Или вы считаете, что в байте 4 бита?
|
|
06.06.2013, 20:29
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
oneguy,
Это всё конечно прекрасно, но не писать же для каждой строковой операции свою функцию. Не зря я наверно сделал бекап windows1251-сайта.
Просто даже не ожидал встретиться с такой проблемой, в Интернете читал статьи, где рекомендуют кодировать скрипты в UTF-8.
|
|
06.06.2013, 20:42
|
Профессор
|
|
Регистрация: 31.05.2012
Сообщений: 396
|
|
Сообщение от Раед
|
oneguy,
Это всё конечно прекрасно, но не писать же для каждой строковой операции свою функцию. Не зря я наверно сделал бекап windows1251-сайта.
|
Ну а что же делать? Можно написать функии на PHP, переводящие строки из UTF-8 в CP1251 и обратно, и применять строковые операции к строкам в CP1251. Но можно использовать первый способ, описанный мной выше, мне кажется, что так делать легче и лучше в большинстве случаев.
|
|
06.06.2013, 20:57
|
|
Тлен
|
|
Регистрация: 02.01.2010
Сообщений: 6,590
|
|
Сообщение от Раед
|
Вы уж определитесь, 8 бит или всё-таки 2 байта. Или вы считаете, что в байте 4 бита?
|
Да как обычно, упоролся, не обращай внимания. Utf-8 использует и 8(на ASCII) и 16 бит(на всё остальное).
Сообщение от Раед
|
oneguy,
Это всё конечно прекрасно, но не писать же для каждой строковой операции свою функцию.
|
Ну они вроде уж кем-то написаны, погуглите.
__________________
29375, 35
|
|
06.06.2013, 20:59
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
Сообщение от oneguy
|
Можно написать функии на PHP, переводящие строки из UTF-8 в CP1251 и обратно, и применять строковые операции к строкам в CP1251
|
Да, была такая идея, и вот реализация.
function str_caller() {
$args = func_get_args();
$f = array_shift($args);
$r = call_user_func_array($f, str_caller_encode($args));
$r = str_caller_encode(array($r), true);
return $r[0];
}
function str_caller_encode($args, $b=false) {
foreach($args as $k => $v) {
if (is_string($v)) {
if ($b) $args[$k] = iconv('windows-1251', 'utf-8', $v);
else $args[$k] = iconv('utf-8', 'windows-1251', $v);
}
if (is_array($v)) $args[$k] = str_caller_encode($v, $b);
}
return $args;
}
Вопрос, на сколько это безопасно. Вдруг какие-либо php-функции таки умеют работать с UTF-8 и неправильно переварят вызванный таким образом cp1251. Не хочется лишней путаницы.
|
|
06.06.2013, 21:13
|
|
''
|
|
Регистрация: 11.12.2011
Сообщений: 636
|
|
И вот ещё, для удобства
function create_utf_str_func($fs) {
foreach ($fs as $v) {
eval("
if (!function_exists(utf_$v)) {
function utf_$v() {
\$args = func_get_args();
array_unshift(\$args, '$v');
return call_user_func_array('str_caller', \$args);
}
}
");
}
}
//например:
create_utf_str_func(array('str_split'));
utf_str_split('some string с русскими буквами');
Вроде работает. Пока буду применять так.
|
|
|
|