note 82050 added to function.split
| From: | lewis | Date: | Tue, 25 Mar 2008 23:32:10 +0000 |
| Subject: | note 82050 added to function.split | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-137582@lists.php.net to get a copy of this message | ||
Those of you trying to use split for CSV, it won't always work as expected. Instead, try using
a simple stack method:
<?php
/**
* Create a 2D array from a CSV string
*
* @param mixed $data 2D array
* @param string $delimiter Field delimiter
* @param string $enclosure Field enclosure
* @param string $newline Line seperator
* @return
*/
function parse($data, $delimiter = ',', $enclosure = '"', $newline =
"\n"){
$pos = $last_pos = -1;
$end = strlen($data);
$row = 0;
$quote_open = false;
$trim_quote = false;
$return = array();
// Create a continuous loop
for ($i = -1;; ++$i){
++$pos;
// Get the positions
$comma_pos = strpos($data, $delimiter, $pos);
$quote_pos = strpos($data, $enclosure, $pos);
$newline_pos = strpos($data, $newline, $pos);
// Which one comes first?
$pos = min(($comma_pos === false) ? $end : $comma_pos, ($quote_pos === false) ? $end :
$quote_pos, ($newline_pos === false) ? $end : $newline_pos);
// Cache it
$char = (isset($data[$pos])) ? $data[$pos] : null;
$done = ($pos == $end);
// It it a special character?
if ($done || $char == $delimiter || $char == $newline){
// Ignore it as we're still in a quote
if ($quote_open && !$done){
continue;
}
$length = $pos - ++$last_pos;
// Is the last thing a quote?
if ($trim_quote){
// Well then get rid of it
--$length;
}
// Get all the contents of this column
$return[$row][] = ($length > 0) ? str_replace($enclosure . $enclosure, $enclosure,
substr($data, $last_pos, $length)) : '';
// And we're done
if ($done){
break;
}
// Save the last position
$last_pos = $pos;
// Next row?
if ($char == $newline){
++$row;
}
$trim_quote = false;
}
// Our quote?
else if ($char == $enclosure){
// Toggle it
if ($quote_open == false){
// It's an opening quote
$quote_open = true;
$trim_quote = false;
// Trim this opening quote?
if ($last_pos + 1 == $pos){
++$last_pos;
}
}
else {
// It's a closing quote
$quote_open = false;
// Trim the last quote?
$trim_quote = true;
}
}
}
return $return;
}
?>
This *should* work for any valid CSV string, regardless of what it contains inside its quotes (using
RFC 4180). It should also be faster than most of the others I've seen. It's very simple in
concept, and thoroughly commented.
----
Server IP: 69.147.83.197
Probable Submitter: 81.140.40.33
----
Manual Page -- http://www.php.net/manual/en/function.split.php
Edit -- https://master.php.net/note/edit/82050
Del: integrated -- https://master.php.net/note/delete/82050/integrated
Del: useless -- https://master.php.net/note/delete/82050/useless
Del: bad code -- https://master.php.net/note/delete/82050/bad+code
Del: spam -- https://master.php.net/note/delete/82050/spam
Del: non-english -- https://master.php.net/note/delete/82050/non-english
Del: in docs -- https://master.php.net/note/delete/82050/in+docs
Del: other reasons-- https://master.php.net/note/delete/82050
Reject -- https://master.php.net/note/reject/82050
Search -- https://master.php.net/manage/user-notes.php