2012-01-27 95 views
2

我有一個包含英文和中文字符(它是從Mozilla Thunderbird電子郵件程序導出的聯繫人列表)的CSV文件。我試圖創建一個可以從這個文件中提取信息的函數。看來函數fgetcsv()不支持多字節字符。由於我運行的是PHP5.2,因此我無法訪問str_getcsv()。如何使用PHP從CSV文件讀取多字節字符

雖然上面的情況指的是英文和中文,但我正在尋找一種適用於任何語言的解決方案。

現在我有函數namecards_import_str_getcsv()作爲我的CSV解析函數,它試圖模仿str_getcsv()。

$file = $_SESSION['namecards_csv_file']; 

    if (file_exists($file->uri)) { 
    // Load raw csv content into a handler variable. 
    $handle = fopen($file->uri, "r"); 
    $cardinfo = array(); 
    while (($data = fgets($handle)) !== FALSE) { 
     $data = namecards_import_str_getcsv($data); 
     dsm($data); 
     $cardinfo[] = $data[0]; 
    } 
    fclose($handle); 
    } 
    else { 
    drupal_set_message(t('CSV file doesn\'t exist'), 'error'); 
    } 

在結果陣列中國字符的字符串是在所述陣列中的正確位置由它們例如顯示爲符號:

function namecards_import_str_getcsv($input, $delimiter = ',', $enclosure = '"', $escape = '\\', $eol = '\n') { 
    if (!function_exists('str_getcsv')) { 
    if (is_string($input) && !empty($input)) { 
     $output = array(); 
     $tmp = preg_split("/".$eol."/",$input); 
     if (is_array($tmp) && !empty($tmp)) { 
     while (list($line_num, $line) = each($tmp)) { 
      if (preg_match("/" . $escape . $enclosure . "/", $line)) { 
      while ($strlen = strlen($line)) { 
       $pos_delimiter = strpos($line, $delimiter); 
       $pos_enclosure_start = strpos($line, $enclosure); 
       if (is_int($pos_delimiter) && is_int($pos_enclosure_start) && ($pos_enclosure_start < $pos_delimiter)) { 
       $enclosed_str = substr($line, 1); 
       $pos_enclosure_end = strpos($enclosed_str, $enclosure); 
       $enclosed_str = substr($enclosed_str, 0, $pos_enclosure_end); 
       $output[$line_num][] = $enclosed_str; 
       $offset = $pos_enclosure_end + 3; 
       } 
       else { 
       if (empty($pos_delimiter) && empty($pos_enclosure_start)) { 
        $output[$line_num][] = substr($line, 0); 
        $offset = strlen($line); 
       } 
       else { 
        $output[$line_num][] = substr($line,0,$pos_delimiter); 
        $offset = (!empty($pos_enclosure_start) && ($pos_enclosure_start < $pos_delimiter))? $pos_enclosure_start : $pos_delimiter + 1; 
       } 
       } 
       $line = substr($line,$offset); 
      } 
      } 
      else { 
      $line = preg_split("/" . $delimiter . "/", $line); 

      /* 
      * Validating against pesky extra line breaks creating false rows. 
      */ 
      if (is_array($line) && !empty($line[0])) { 
       $output[$line_num] = $line; 
      } 
      } 
     } 
     return $output; 
     } 
     else { 
     return false; 
     } 
    } 
    else { 
     return false; 
    } 
    } 
    else { 
    return str_getcsv($input); 
    } 
} 

這個功能是通過下面的行的代碼調用「С」。

在此之前我嘗試過的另一種方法是簡單地使用fgetcsv()(請參見下面的示例)。但在這種情況下,返回數組的元素是空的。

$file = $_SESSION['namecards_csv_file']; 

if (file_exists($file->uri)) { 
    // Load raw csv content into a handler variable. 
    $handle = fopen($file->uri, "r"); 
    $cardinfo = array(); 
    while (($data = fgetcsv($handle, 5000, ",")) !== FALSE) { 
    dsm($data); 
    $cardinfo[] = $data; 
    } 
    fclose($handle); 
} 
else { 
    drupal_set_message(t('CSV file doesn\'t exist'), 'error'); 
} 

如果你有興趣在這裏是CSV文件的內容:

First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes, 
Ben,Gunn,Ben Gunn,Benny,[email protected],[email protected],,+94 (10) 11111111,+94 (10) 22222222,+94 (10) 33333333,,+94 44444444444,12 Benny Lane,,Beijing,Beijing,100028,China,13 asdfsdfs,,sdfsf,sdfsdf,134323,China,Manager,Sales,Benny Inc,,,,,,,,,,, 
喬,康,喬 康,小康,,,,,,,,,,,,,,,北京市朝陽區,,,,,,,,,,,,,,,,,,, 
+2

據我所見,fgetcsv()應該支持多字節字符。是什麼讓你覺得它不?你確定問題不在其他地方嗎? – 2012-01-27 10:52:58

+1

@Pekka'fgetcsv()'以字節爲單位檢查分隔符,所以如果分隔符**字節**可以是多字節**序列的一部分**則事情開始中斷。 – 2012-01-27 10:56:52

+2

@Eugen啊,你說得對。但是,應該不會發生與單字節字節匹配的多字節字節,至少在UTF-8中不會發生這種情況嗎?在UTF-8中唯一的一個不是否定的是一個多字節分隔符(**編輯:** ahh,我猜它可能會在第二個字節中發生,你說得對。 ) – 2012-01-27 10:58:22

回答

2

只是寫了一個答案什麼的評論想通了:

fgetcsv是locale敏感,所以請確保將setlocale設置爲UTF-8語言環境。

相關問題