如果它是变音符号,fgetcsv正在吃字符串的第一个字母

时间:2012-09-12 14:47:01

标签: php xml csv character-encoding diacritics

我正在将Excel生成的CSV文件中的内容导入XML文档,如:

$csv = fopen($csvfile, r);
$words = array();

while (($pair = fgetcsv($csv)) !== FALSE) {
    array_push($words, array('en' => $pair[0], 'de' => $pair[1]));
}

插入的数据是英语/德语表达。

我将这些值插入XML结构并输出XML,如下所示:

$dictionary = new SimpleXMLElement('<dictionary></dictionary>');
//do things
$dom = dom_import_simplexml($dictionary) -> ownerDocument;
$dom -> formatOutput = true;

header('Content-encoding: utf-8'); //<3 UTF-8
header('Content-type: text/xml'); //Headers set to correct mime-type for XML output!!!!

echo $dom -> saveXML();

这工作正常,但我遇到一个非常奇怪的问题。如果字符串的第一个字母是变音符号(如ÖsterreichÄgypten),则该字符将被省略,从而产生gyptensterreich。如果变音符号位于字符串(Russische Föderation)的中间,则会正确传输。同样适用于ßé等等。

所有文件均采用UTF-8编码,并以UTF-8格式提供。

对我来说,这似乎很奇怪,而且我可能会错过一些东西,这里有很多聪明的人。

5 个答案:

答案 0 :(得分:4)

好的,所以这似乎是fgetcsv中的一个错误。

我现在正在处理我自己的CSV数据(有点麻烦),但它正在运行,我根本没有任何编码问题。

这是我正在做的(尚未优化的版本):

$rawCSV = file_get_contents($csvfile);

$lines = preg_split ('/$\R?^/m', $rawCSV); //split on line breaks in all operating systems: http://stackoverflow.com/a/7498886/797194

foreach ($lines as $line) {
    array_push($words, getCSVValues($line));
}

getCSVValues来自 here ,需要像这样处理CSV行(逗号!):

"I'm a string, what should I do when I need commas?",Howdy there

看起来像:

function getCSVValues($string, $separator=","){

    $elements = explode($separator, $string);

    for ($i = 0; $i < count($elements); $i++) {
        $nquotes = substr_count($elements[$i], '"');
        if ($nquotes %2 == 1) {
            for ($j = $i+1; $j < count($elements); $j++) {
                if (substr_count($elements[$j], '"') %2 == 1) { // Look for an odd-number of quotes
                    // Put the quoted string's pieces back together again
                    array_splice($elements, $i, $j-$i+1,
                        implode($separator, array_slice($elements, $i, $j-$i+1)));
                    break;
                }
            }
        }
        if ($nquotes > 0) {
            // Remove first and last quotes, then merge pairs of quotes
            $qstr =& $elements[$i];
            $qstr = substr_replace($qstr, '', strpos($qstr, '"'), 1);
            $qstr = substr_replace($qstr, '', strrpos($qstr, '"'), 1);
            $qstr = str_replace('""', '"', $qstr);
        }
    }
    return $elements;

}

相当多的解决方法,但似乎工作正常。

修改

还有一个 filed bug ,显然这取决于区域设置。

答案 1 :(得分:3)

如果字符串来自Excel(我遇到字母ø消失的问题,如果它在字符串的开头就消失了)......那么就修复了它:

setlocale(LC_ALL,'en_US.ISO-8859-1');

答案 2 :(得分:2)

如果中间的其他变音符号显示正常,那么这不是基本编码问题。它发生在行的开头可能表明与换行符不兼容。也许CSV是使用不同的换行编码生成的。

在不同操作系统之间移动文件时会发生这种情况:

  • Windows:\r\n(字符13和10)
  • Linux:\n(字符10)
  • Mac OS:\r(字符13)

如果我是你,我会确认换行标记是否确定。

如果在Linux中:hexdump -C filename | more并检查文档。

如果是这种情况,您可以使用sed表达式更改换行符。

希望有所帮助!

答案 3 :(得分:2)

更简单的解决方法(但很脏):

//1. replace delimiter in input string with delimiter + some constant
$dataLine = str_replace($this->fieldDelimiter, $this->fieldDelimiter . $this->bugFixer, $dataLine);

//2. parse
$parsedLine = str_getcsv($dataLine, $this->fieldDelimiter);

//3. remove the constant from resulting strings.
foreach ($parsedLine as $i => $parsedField)
{
    $parsedLine[$i] = str_replace($this->bugFixer, '', $parsedField);
}

答案 4 :(得分:0)

可能是某种utf8_encode()问题。文档页面上的This comment似乎表明,如果你已经编码过Umlaut,它可能会导致问题。

也许测试一下,看看数据是否已经用mb_detect_encoding()进行了utf-8编码。