Php 在分隔符(;)和分隔符(,)上分解csv文件?

Php 在分隔符(;)和分隔符(,)上分解csv文件?,php,codeigniter,csv,Php,Codeigniter,Csv,当我在分隔符(;)上分解csv文件时 在某些excel程序中爆炸成功,而在其他程序中爆炸失败 另外,当我在分隔符(,)上分解csv文件时 在某些excel程序中爆炸成功,而在其他程序中爆炸失败 如何在所有版本的excel中进行分解? 我怎么知道要爆炸的完美分隔符 是的,有密码 if (!function_exists('create_csv')) { function create_csv($query, &$filename = false, $old_csv = false)

当我在分隔符(;)上分解csv文件时 在某些excel程序中爆炸成功,而在其他程序中爆炸失败

另外,当我在分隔符(,)上分解csv文件时 在某些excel程序中爆炸成功,而在其他程序中爆炸失败

如何在所有版本的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=“;”; 有时$delimiter=“,”


谢谢。

没有办法100%确定您的目标是真正的分隔符。你所能做的就是猜测

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

要查找分隔符,基本上需要一个计算
数量的函数返回较大的值

比如:

$array = explode(find_delimiter($csv), $csv);
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]);
}
希望有帮助;)

编辑:您的
find_delimiter
函数可能类似于:

$array = explode(find_delimiter($csv), $csv);
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]);
}

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


但是,一旦确定(或需要特定的)分隔符格式。您可能会发现php的内置策略比基于手动
explode
的策略更简单、更准确。

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

function delimiter_exists($csvHeader, $delimiter) {
    return (bool)preg_match("/$delimiter/", $csvHeader);
}
$csvHeader = "abc;def";
$delimiter = delimiter_exists($csvHeader, ',') ? ',' : ';';
“姓名、价值”、其他姓名、其他价值、姓氏;最后值

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

但是,如果您的CSV文件格式正确,那么您可能会在任何一行中找到正确的分隔符。因此,您可以尝试创建一些函数,如@johnkork建议的find_delimiter($csvLine),但问题是函数本身不知道要搜索哪个分隔符。但是,您完全知道所有可能的分隔符,因此您可以尝试创建另一个类似于delimiter_exists($csvLine,$delimiter)的函数,该函数返回true或false

但即使函数分隔符_存在($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, ',') ? ',' : ';';
对于您的具体情况,您可以这样使用:

function delimiter_exists($csvHeader, $delimiter) {
    return (bool)preg_match("/$delimiter/", $csvHeader);
}
$csvHeader = "abc;def";
$delimiter = delimiter_exists($csvHeader, ',') ? ',' : ';';

希望这有帮助

如果您对预期数据(列数)有一个概念,那么这可能是一个很好的猜测,并且可能是比较哪种情况发生得最多(取决于您预期的数据类型)的一个很好的替代方法。 我想,如果你有头球记录,效果会更好。(您可以检查特定的标题值)

很抱歉,没有将它融入到您的代码中,但我不确定您正在进行的调用是什么,但您应该能够适应它

$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 . ")");  
}

例如,如果所有或大部分字段都包含非整数(例如,货币金额列表)且没有标题记录,则不要使用此选项,因为文件之间用
分隔
最有可能使用
作为小数点,并且可能有相同数量的逗号和分号。

您可以使用helper函数检测最佳分隔符,如:

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;
}

你不能。任何MS Excel实例使用的分隔符都是特定于区域设置的,通常基于其配置的国家/地区是使用
还是
作为十进制分隔符。。。。。a
更常见,但没有通用的答案。。。。如果有,你甚至不需要问Kit为什么CSV不是Excel本机格式的好替代格式的一个原因你有一些代码给我们看吗?您是在尝试读取文件然后分解行,还是在使用fgetcsv?您不能。但是一个好的猜测是对所有常用分隔符进行计数,看看哪一个具有最高计数。您的文件是否有头记录?如果是这样,您可以同时尝试这两种方法,并查看哪一种与预期数据匹配。实际上,find_delimiter函数能够搜索无限给定的潜在分隔符列表(请参阅$arrdimiters数组)。如您所述,浏览CSV文件的标题部分是一个好主意,因为它混合了“假阳性”单元格,如带有小数和comas的数字