使用 str_getcsv 和 fgetcsv 将 CSV 数据转换为 PHP 数组时保留整数和浮点类型

Keep Integer and Float Types When Converting CSV Data to PHP Arrays With str_getcsv and fgetcsv

当使用 PHPs str_getcsv-函数数字将被视为字符串:

<?php
$csv = str_getcsv('0,1.2,"string"');
var_dump( $csv );
/* result: array(3) {
  [0]=>string(1) "0"
  [1]=>string(3) "1.2"
  [2]=>string(6) "string"
} */
/* DESIRED result: array(3) {
  [0]=>int(0)
  [1]=>float(1.2)
  [2]=>string(6) "string"
} */

fgetcsv函数也是如此。如何克服这个问题而不在之后迭代数组并手动转换回每个值 - 可以这么说。

只是为了说清楚 - 我不是在寻求像这样的解决方法:

<?php
$csv = str_getcsv('0,1.2,"string"');
foreach ( $csv as &$v ) if ( is_numeric( $v ) ) $v += 0;
var_dump( $csv ); // desired result

因为我要处理相当多的数据,所以性能对我来说很重要。

我们可以将其作为副本关闭,但我很无聊。 json_decode 将解码为 intfloatboolean,并且比其他方法更快:

function str_getcsv_typed($string, $delimiter=",", enclosure='"', $escape = "\") {
    return json_decode('[' . str_getcsv($string, $delimiter, enclosure, $escape) . ']');
}

function file_getcsv_typed($handle, $length=0, $delimiter=",", enclosure='"', $escape = "\") {
    return json_decode('[' . fgetcsv($handle, $length, $delimiter, enclosure, $escape) . ']');
}

如果您的 CSV 中碰巧有 JSON 对象或数组格式的任何内容,那么它也可能会解码这些内容,也许不是您想要的。此外,如果有任何非法 JSON 字符或语法,它也会失败。

看来很遗憾,除了变通办法别无他法!有一些选择可以做到这一点,并且没有“唯一的方法”。根据每个用例,可能会有不同的解决方案。对于我的情况,我将使用以下代码。

<?php
$csv = '0,1.2,"string"';
json_decode( "[$csv]", true );

但请注意,这至少会在多行值时失败!

这里有一些测试:

<?php
$csv = '0,1.2,"string"';
var_dump(
  json_decode( "[$csv]", true ) // works
  , str_getcsv( $csv )          // converts everything to string
);
/*
array(3) { json_decode
  [0]=>int(0)
  [1]=>float(1.2)
  [2]=>string(6) "string"
}
array(3) { str_getcsv
  [0]=>
  string(1) "0"
  [1]=>
  string(3) "1.2"
  [2]=>
  string(6) "string"
}
*/
$csv = '", as value in ,-separated csv"';
var_dump(
  json_decode( "[$csv]", true ) // works also when separator is part of value
  , str_getcsv( $csv )          // works also when separator is part of value but converts everything to string
);
/*
array(1) { json_decode
  [0]=>string(29) ", as value in ,-separated csv"
}
array(1) { str_getcsv
  [0]=>string(29) ", as value in ,-separated csv"
}
*/
$csv = '0,"value
with multiline"';
var_dump(
  json_decode( "[$csv]", true ) // doesn't work as JSON can't handle multilines
  , str_getcsv( $csv )          // works also with multilines but converts everything to string
);
/*
NULL json_decode
array(2) { str_getcsv
  [0]=>string(1) "0"
  [1]=>string(21) "value
              with multiline"
}
*/

我最初问题的版本似乎是一种非常稳健的方法,因为它依赖于本机 str_getcsv 函数并随后转换为适当的类型。就性能而言,这对我来说听起来不太理想,但这应该只是处理非常重的字符串时的一个问题(对我来说就是这种情况)。

<?php
$csv = str_getcsv('0,1.2,"string"');
foreach ( $csv as &$v ) if ( is_numeric( $v ) ) $v += 0;