将PHP数组转换为CSV字符串

23

我有几种方法可以从stackoverflow和google将php数组转换为csv字符串。但是我遇到了一个问题,如果我想存储像01727499452这样的手机号码,它会保存为没有第一个0的值。

我目前正在使用以下代码:

将数组转换为csv

请问有人能帮助我吗。

Array   

[1] => Array
    (
        [0] => Lalu ' " ; \\ Kumar
        [1] => Mondal
        [2] => 01934298345
        [3] => 
    )

[2] => Array
    (
        [0] => Pritom
        [1] => Kumar Mondal
        [2] => 01727499452
        [3] => Bit Mascot
    )

[3] => Array
    (
        [0] => Pritom
        [1] => Kumar Mondal
        [2] => 01711511149
        [3] => 
    )

[4] => Array
    (
        [0] => Raaz
        [1] => Mukherzee
        [2] => 01911224589
        [3] => Khulna University 06
    )

我的代码块:

function arrayToCsv( array $fields, $delimiter = ';', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
$delimiter_esc = preg_quote($delimiter, '/');
$enclosure_esc = preg_quote($enclosure, '/');

$outputString = "";
foreach($fields as $tempFields) {
    $output = array();
    foreach ( $tempFields as $field ) {
        if ($field === null && $nullToMysqlNull) {
            $output[] = 'NULL';
            continue;
        }

        // Enclose fields containing $delimiter, $enclosure or whitespace
        if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
            $field = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field) . $enclosure;
        }
        $output[] = $field." ";
    }
    $outputString .= implode( $delimiter, $output )."\r\n";
}
return $outputString; }

谢谢,

Pritom。


2
使用别人的轮子就会出现这样的问题。 - Ben
3
将其保存为字符串。对于电话号码,我建议这样做,因为您可能还希望保存"+"号 ;) - SBI
4
你应该使用 PHP 内置的 CSV 函数,例如 http://php.net/manual/en/function.fputcsv.php。 - cryptic ツ
1
一些二手建议:如果你不打算对其进行算术运算,请将其存储为字符串。The Daily WTF包含许多以科学计数法打印的电话号码的示例,这最终源于有人将其存储为整数。 - michaelb958--GoFundMonica
1
数字将以前导零的形式正确存储在CSV中,但是当在MS Excel中打开时,Excel会重新格式化它 - 要么使用已经支持格式信息的文件格式(不是CSV),这样Excel就不会应用其标准行为,要么在保存时强制将其作为公式字符串 ="01911224589" - Mark Baker
显示剩余2条评论
10个回答

41

你可以使用 str_putcsv 函数:

if(!function_exists('str_putcsv'))
{
    function str_putcsv($input, $delimiter = ',', $enclosure = '"')
    {
        // Open a memory "file" for read/write...
        $fp = fopen('php://temp', 'r+');
        // ... write the $input array to the "file" using fputcsv()...
        fputcsv($fp, $input, $delimiter, $enclosure);
        // ... rewind the "file" so we can read what we just wrote...
        rewind($fp);
        // ... read the entire line into a variable...
        $data = fread($fp, 1048576);
        // ... close the "file"...
        fclose($fp);
        // ... and return the $data to the caller, with the trailing newline from fgets() removed.
        return rtrim($data, "\n");
    }
 }

 $csvString = '';
 foreach ($list as $fields) {
     $csvString .= str_putcsv($fields);
 }

更多相关内容请访问GitHub,此函数由@johanmeiring创建。


1
这只是小问题,但我认为你的意思是 $csvString .= str_putcsv($fp, $fields);。漏了个 $ ;) - Mr. Concolato
7
应该使用str_putcsv($fields);而不是str_putcsv($fp, $fields); - bamboofighter
2
我喜欢这个解决方案。当我“借用”它时,我进行了一些小修改: ... $len = ftell($fp)+1; rewind($fp); $data = fread($fp,$len); ... 看起来它能够工作。我不知道1048576代表什么,所以我不想直接使用它。 - Ghost8472
为什么不使用某人称为Dave(在多年前发布的)链接中的原始函数$data = fgets($fp);(从而避免硬编码1048576)?但有没有人知道为什么他得到了-1分,尽管它似乎工作良好? - LWC

26

这就是你所需要的

$out = "";
foreach($array as $arr) {
    $out .= implode(",", $arr) . PHP_EOL;

}
它遍历您的数组,在每次循环中创建一个新行,并使用“,”分隔数组值。

这是我想要的吗?请阅读我的问题,如果您不清楚,请问我。 - Pritom
应该可以,我不明白为什么你不愿意 :) 试一试,看看它是否符合你的期望。 - Daniel Mensing
12
我在许多情况下都使用了类似的东西,如果有一个逗号','字符在$arr中的某个值上会导致出错。CSV格式有处理这种情况的方法,但这个解决方案没有考虑到。此外,在编码Windows特定的新行时使用"\r\n"可能会在某些情况下引起问题。使用常量PHP_EOL将得到更具可移植性的代码。 - jbo5112
1
OP 可以尝试检查 $out 的内容。 - billrichards
1
没有适当地转义输出。预计会出现损坏的数据。 - Walf

6

受@alexcristea回答的启发:

function array2csv($data, $delimiter = ',', $enclosure = '"', $escape_char = "\\")
{
    $f = fopen('php://memory', 'r+');
    foreach ($data as $item) {
        fputcsv($f, $item, $delimiter, $enclosure, $escape_char);
    }
    rewind($f);
    return stream_get_contents($f);
}

$list = array (
    array('aaa', 'bbb', 'ccc', 'dddd'),
    array('123', '456', '789'),
    array('"aaa"', '"bbb"')
);
var_dump(array2csv($list));

3

您确定这些数字是否实际上保存时没有前导零吗?您是否查看了文本编辑器中的实际CSV输出?

如果您只是在电子表格应用程序中打开CSV文件,很可能是电子表格将您的电话号码解释为数值,并在显示时删除零。您通常可以通过更改该特定列的格式选项来在电子表格中修复此问题。


0

这里是一个更通用的解决方案。我实际上正在寻找一种为 SQL 批量插入创建字符串列表的方法。代码将如下所示:

foreach ($rows as $row) {
    $string = toDelimitedString($row);
    // Now append it to a file, add line break, whatever the need may be
}

这是我最终添加到工具包中的有用函数:

/**
 * Convert an array of strings to a delimited string. This function supports CSV as well as SQL output since
 * the quote character is customisable and the escaping behaviour is the same for CSV and SQL.
 *
 * Tests:
 *  echo toDelimitedString([], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A'], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A', 'B'], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A', 'B\'C'], ',', '\'', true) . "\n";
 *  echo toDelimitedString([], ',', '\'', true) . "\n";
 *  echo toDelimitedString(['A'], ',', '"', true) . "\n";
 *  echo toDelimitedString(['A', 'B'], ',', '"', true) . "\n";
 *  echo toDelimitedString(['A', 'B"C'], ',', '"', true) . "\n";
 *
 * Outputs:
 *  <Empty String>
 *  'A'
 *  'A','B'
 *  'A','B''C'
 *  <Empty String>
 *  "A"
 *  "A","B"
 *  "A","B""C"
 *
 * @param array $array A one-dimensional array of string literals
 * @param string $delimiter The character to separate string parts
 * @param string $quoteChar The optional quote character to surround strings with
 * @param bool $escape Flag to indicate whether instances of the quote character should be escaped
 * @return string
 */
function toDelimitedString(array $array, string $delimiter = ',', string $quoteChar = '"', bool $escape = true)
{
    // Escape the quote character, since it is somewhat expensive it can be suppressed
    if ($escape && !empty($quoteChar)) {
        $array = str_replace($quoteChar, $quoteChar . $quoteChar, $array);
    }

    // Put quotes and commas between all the values
    $values = implode($array, $quoteChar . $delimiter . $quoteChar);

    // Put first and last quote around the list, but only if it is not empty
    if (strlen($values) > 0) {
        $values = $quoteChar . $values . $quoteChar;
    }

    return $values;
}

0

由于它是 CSV 而不是 JSON,所以所有内容都将被读取为字符串,因此只需使用以下方法将数字转换为字符串:

  • (string)$variable
  • strval($variable)(我更喜欢这个)
  • 使用空字符串连接,如$variable . ''

PHP 的 gettype() 也是一种选择。您可以使用我描述的方法之一将每个字段强制转换为字符串(即使它已经是一个字符串),或者您可以通过执行以下操作来调用您想要的数字字段:

if (gettype($field) == 'integer' || gettype($field) == 'double') {
    $field = strval($field); // Change $field to string if it's a numeric type
}

这是完整代码,添加了它

function arrayToCsv( array $fields, $delimiter = ';', $enclosure = '"', $encloseAll = false, $nullToMysqlNull = false ) {
    $delimiter_esc = preg_quote($delimiter, '/');
    $enclosure_esc = preg_quote($enclosure, '/');

    $outputString = "";
    foreach($fields as $tempFields) {
        $output = array();
        foreach ( $tempFields as $field ) {
            // ADDITIONS BEGIN HERE
            if (gettype($field) == 'integer' || gettype($field) == 'double') {
                $field = strval($field); // Change $field to string if it's a numeric type
            }
            // ADDITIONS END HERE
            if ($field === null && $nullToMysqlNull) {
                $output[] = 'NULL';
                continue;
            }

            // Enclose fields containing $delimiter, $enclosure or whitespace
            if ( $encloseAll || preg_match( "/(?:${delimiter_esc}|${enclosure_esc}|\s)/", $field ) ) {
                $field = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $field) . $enclosure;
            }
            $output[] = $field." ";
        }
        $outputString .= implode( $delimiter, $output )."\r\n";
    }
    return $outputString; 
}

0
这对我来说很有效,并且它是基于PHP内置的CSV函数。其中一个巧妙之处在于它会自动正确地在相关字段周围添加引号。
// Create an array of elements
$list = array(
    ['Name', 'age', 'Gender'],
    ['Bob', 20, 'Male'],
    ['John', 25, 'Male'],
    ['Jessica', 30, 'Female']
);

// Create an output buffer
$outputBuffer = fopen('php://temp', 'w');

// Loop through the array and write to the output buffer
foreach ($list as $fields) {
    fputcsv($outputBuffer, $fields);
}

// Rewind the output buffer
rewind($outputBuffer);

// Read the contents of the output buffer
$csvString = stream_get_contents($outputBuffer);

// Close the output buffer
fclose($outputBuffer);

// Output the CSV string
echo $csvString;

-1

这个实现不使用文件指针,不应无意中修改传递给它的任何数据,并且仅在需要时进行转义,类似于fputcsv()(但没有$escape_char的麻烦):

function str_putcsv(array $fields, string $delimiter = ',', string $enclosure = '"') {
    $escs = [];
    foreach ($fields as $field) {
        $esc = (string) $field;
        if (
            false !== strpos($esc, $delimiter)
            || false !== strpos($esc, $enclosure)
        ) {
            $esc = $enclosure . strtr($esc, ["$enclosure" => "$enclosure$enclosure"]) . $enclosure;
        }
        $escs[] = $esc;
    }
    return implode($delimiter, $escs) . PHP_EOL;
}

如果你的PHP版本不支持字符串类型声明,可以省略string类型声明。

-2
我正在使用这个函数将PHP数组转换为CSV。它也适用于多维数组。
public function array_2_csv($array) {
$csv = array();
foreach ($array as $item=>$val) {
if (is_array($val)) { 
    $csv[] = $this->array_2_csv($val);
    $csv[] = "\n";
} else {
    $csv[] = $val;
  }
 }
return implode(';', $csv);
}

-2
上面的函数并不完全正确,因为它将 \n 视为一个元素,这不是我们想要的,因为每行必须仅由 \n 分隔。因此,更有效的代码应该是:
function array2csv($array, $delimiter = "\n") {
    $csv = array();
    foreach ($array as $item=>$val) 
    {
        if (is_array($val)) 
        { 
            $csv[] = $this->array2csv($val, ";");
        } 
        else 
        {
            $csv[] = $val;
        }
    }
    return implode($delimiter, $csv);
}

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