Отсутствует первый символ полей в CSV - PullRequest
5 голосов
/ 22 апреля 2011

Я работаю над сценарием импорта CSV в PHP. Работает нормально, за исключением иностранных символов в начале поля.

код выглядит так

if (($handle = fopen($filename, "r")) !== FALSE)
{
     while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) 
         $teljing[] = $data;

     fclose($handle);
}

Вот пример данных, показывающих мою проблему

føroyskir stavir, "Kr. 201,50"
óvirkin ting, "Kr. 100,00"

Это приведет к следующему

array 
(
     [0] => array 
          (
                 [0] => 'føroyskir stavir',
                 [1] => 'Kr. 201,50'
          )
     [1] => array 
          (
                 [0] => 'virkin ting', <--- Should be 'óvirkin ting'
                 [1] => 'Kr. 100,00'
          )
)

Я видел это поведение, задокументированное в некоторых комментариях на php.net, и я пытался ini_set('auto_detect_line_endings',TRUE); обнаружить окончания строк. Безуспешно.

Кто-нибудь знаком с этой проблемой?

Редактировать:

Спасибо, AJ, теперь эта проблема решена.

setlocale(LC_ALL, 'en_US.UTF-8');

Было решение.

Ответы [ 2 ]

6 голосов
/ 22 апреля 2011

Из руководства PHP для fgetcsv():

«Примечание. Эта функция учитывает настройку локали. Если LANG, например, en_US.UTF-8, файлы с однобайтовой кодировкой считываются неправильно этой функцией».

0 голосов
/ 22 апреля 2011

Скопировано из комментариев PHP.net/fgetcsv:

kent at marketruler dot com 04-Feb-2010 11:18 Обратите внимание, что fgetcsv, по крайней мере, в PHP 5.3или предыдущий, НЕ будет работать с файлами в кодировке UTF-16.Вы можете преобразовать весь файл в ISO-8859-1 (или latin1) или преобразовать строку за строкой и преобразовать каждую строку в кодировку ISO-8859-1, а затем использовать str_getcsv (или совместимую обратно-совместимую реализацию).Если вам нужно читать нелатинские алфавиты, вероятно, лучше всего конвертировать в UTF-8.

См. Str_getcsv для его обратно-совместимой версии с PHP <5.3 и смотрите utf8_decode для функции, написанной Расмусом Андерссономкоторый предоставляет utf16_decode.Модификация, которую я добавил, заключалась в том, что BOP появляется вверху файла, а не в последующих строках.Таким образом, вам нужно сохранить порядковый номер, а затем повторно отправлять его при каждом последующем декодировании строки.Эта измененная версия возвращает порядковый номер, если он недоступен: </p>

<?php
/**
 * Decode UTF-16 encoded strings.
 *
 * Can handle both BOM'ed data and un-BOM'ed data.
 * Assumes Big-Endian byte order if no BOM is available.
 * From: http://php.net/manual/en/function.utf8-decode.php
 *
 * @param   string  $str  UTF-16 encoded data to decode.
 * @return  string  UTF-8 / ISO encoded data.
 * @access  public
 * @version 0.1 / 2005-01-19
 * @author  Rasmus Andersson {@link http://rasmusandersson.se/}
 * @package Groupies
 */
function utf16_decode($str, &$be=null) {
    if (strlen($str) < 2) {
        return $str;
    }
    $c0 = ord($str{0});
    $c1 = ord($str{1});
    $start = 0;
    if ($c0 == 0xFE && $c1 == 0xFF) {
        $be = true;
        $start = 2;
    } else if ($c0 == 0xFF && $c1 == 0xFE) {
        $start = 2;
        $be = false;
    }
    if ($be === null) {
        $be = true;
    }
    $len = strlen($str);
    $newstr = '';
    for ($i = $start; $i < $len; $i += 2) {
        if ($be) {
            $val = ord($str{$i})   << 4;
            $val += ord($str{$i+1});
        } else {
            $val = ord($str{$i+1}) << 4;
            $val += ord($str{$i});
        }
        $newstr .= ($val == 0x228) ? "\n" : chr($val);
    }
    return $newstr;
}
?>

Trying the "setlocale" trick did not work for me, e.g.

<?php
setlocale(LC_CTYPE, "en.UTF16");
$line = fgetcsv($file, ...)
?>

Но это возможно, потому что моя платформа не поддерживала его.Тем не менее, fgetcsv поддерживает только одиночные символы для разделителя и т. Д. И жалуется, если вы передаете UTF-16 версию указанного символа, поэтому я довольно быстро отказался от этого.

Надеюсь, это кому-то поможеттам.

...