在分隔符(; )和分隔符(,)上拆分CSV文件?

6
当我使用分隔符(;)拆分CSV文件时,有些Excel程序可以成功拆分,而有些则失败了。同样地,当我使用分隔符(,)拆分CSV文件时,也存在这种情况。如何在所有版本的Excel中进行拆分?如何确定最佳的分隔符进行拆分?是的,有代码存在。
if (!function_exists('create_csv')) {
    function create_csv($query, &$filename = false, $old_csv = false) {
        if(!$filename) $filename = "data_export_".date("Y-m-d").".csv";
        $ci = &get_instance();
        $ci->load->helper('download');
        $ci->load->dbutil();
        $delimiter = ";";
        $newline = "\r\n";
        $csv = "Data:".date("Y-m-d").$newline;
        if($old_csv)
            $csv .= $old_csv;
        else
            $csv .= $ci->dbutil->csv_from_result($query, $delimiter, $newline);
        $columns = explode($newline, $csv);
        $titles = explode($delimiter, $columns[1]);
        $new_titles = array();
        foreach ($titles as $item) {
            array_push($new_titles, lang(trim($item,'"')));
        }
        $columns[1] = implode($delimiter, $new_titles);
        $csv = implode($newline, $columns);
        return $csv;
    }
}

有时我会将 $delimiter 设置为";",有时则为","。谢谢。

2
你不能。任何MS Excel实例使用的定界符都是特定于区域设置的,通常基于其配置的国家是否使用,.作为十进制分隔符...... ;更为常见,但没有通用答案......如果有的话,您甚至都不需要询问。 - Mark Baker
这就是为什么CSV不是一种好的格式来替代Excel本地格式的原因之一。 - Mark Baker
你有一些代码可以展示给我们吗?你是尝试读取文件并拆分行,还是使用fgetcsv? - foxbeefly
你无法确定。但是一个好的猜测是计算所有常见分隔符,并查看哪个计数最高。 - Alex Tartan
你的文件是否有头记录?如果是这样,你可以尝试两种方法,看哪一种与预期数据匹配。 - komodosp
5个回答

1
如果您已经有预期数据的想法(列数),那么这可能是一个很好的猜测,并且可能是比较哪个最多的良好替代方法(取决于您所期望的数据类型)。如果您有标题记录,它将工作得更好,我想象。 (您可以放置特定标题值的检查)抱歉,无法将其适应您的代码,但我不太确定您正在进行的调用是什么,但您应该能够适应它。
$expected_num_of_columns = 10;
$delimiter = "";

foreach (array(",", ";") as $test_delimiter) {
   $fid = fopen ($filename, "r");
   $csv_row = fgetcsv($fid, 0, $test_delimiter);
   if (count($csv_row) == $expected_num_of_columns) {
       $delimiter = $test_delimiter;
       break;
   }
   fclose($fid);
}

if (empty($delimiter)) {
   die ("Input file did not contain the correct number of fields (" . $expected_num_of_columns . ")");  
}

如果字段中包含非整数数字(例如货币金额列表)并且没有标题记录,请勿使用此选项,因为使用;分隔的文件很可能使用,作为小数点,并且逗号和分号数量可能相同。


1
你可以使用辅助函数来检测最佳分隔符,例如:
public function find_delimiter($csv)
{
    $delimiters = array(',', '.', ';');
    $bestDelimiter = false;
    $count = 0;
    foreach ($delimiters as $delimiter)
        if (substr_count($csv, $delimiter) > $count) {
            $count = substr_count($csv, $delimiter);
            $bestDelimiter = $delimiter;
        }
    return $bestDelimiter;
}

0

简短的回答是,除非你能应用一些启发式方法来确定文件格式,否则你可能无法解析它。如果你不知道并且无法检测到正在解析的文件的格式,那么解析它将会很困难。

然而,一旦你确定了(或者需要一个特定的)分隔符格式,你可能会发现php内置的fgetcsv比手动基于explode的策略更容易和准确。


0

无法百分之百确定您是否针对真正的分隔符。您能做的就是猜测。

您应该首先找到正确的分隔符,然后在此分隔符上拆分 CSV。

要查找分隔符,基本上,您需要一个函数来计算;的数量,并返回较大的那个。

类似于:

$array = explode(find_delimiter($csv), $csv);

希望能有所帮助;)
编辑:你的find_delimiter函数可以是这样的:
function find_delimiter($csv)
{
   $arrDelimiters = array(',', '.', ';');
   $arrResults = array();
   foreach ($arrDelimiters as $delimiter)
   {
       $arrResults[$delimiter] = count(explode($delimiter, $csv));
   }
   $arrResults = rsort($arrResults);
   return (array_keys($arrResults)[0]);
}

0

好的,看起来您已经确切知道您的分隔符将是“,”或“;”。这是一个很好的起点。因此,您可以尝试将所有逗号(,)替换为分号(;),然后仅按分号扩展。但是,在这种方法中,您肯定会在某些情况下遇到问题,因为您的 CSV 文件的某些行可能是这样的:

"名称,值",其他名称,其他值,姓氏;最后的价值

这样,如果您的 CSV 文件有四列,则其分隔符将是逗号。但是,将逗号更改为分号会得到五列,这是不正确的。因此,将某些分隔符更改为另一个分隔符并不是一个好方法。

但是,如果您的 CSV 文件格式正确,则可以在任何一行中找到正确的分隔符。因此,您可以尝试创建一些类似于@johnkork提出的find_delimiter($csvLine)的函数,但是该函数本身无法知道要搜索哪个分隔符。但是,您确切地知道所有可能的分隔符,因此可以尝试创建另一个相当类似的函数delimiter_exists($csvLine,$delimiter),它返回 true 或 false。

但是,即使是函数delimiter_exists($csvLine, $delimiter)也不足够。为什么?因为对于上面提供的CSV行实例,您会发现逗号“,”和分号“;”都是存在的分隔符。对于逗号,它将是一个具有四列的CSV文件,而对于分号,则是两列。

因此,没有通用的方法可以确切地获得您想要的内容。然而,可能还有另一种检查的方法-CSV文件的第一行,假设您的CSV文件有标题。大多数情况下,CSV文件中的标题除了由特定分隔符分隔的列的字母数字名称之外,没有其他符号(不一定)。因此,您可以尝试创建像delimiter_exists($csvHeader, $delimiter)这样的函数,其实现可能如下:

function delimiter_exists($csvHeader, $delimiter) {
    return (bool)preg_match("/$delimiter/", $csvHeader);
}

对于您的特定情况,您可以像这样使用它:

$csvHeader = "abc;def";
$delimiter = delimiter_exists($csvHeader, ',') ? ',' : ';';

希望这可以帮到你!

实际上,find_delimiter函数能够搜索一个无限给定的潜在分隔符列表(请参见$arrDelimiters数组)。 按照您所提到的CSV文件的标题部分进行操作是一个好主意,因为它可以避免出现“误报”单元格,例如带有小数和逗号的数字。 :) - johnkork

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接