1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace CsvParser\Reader; |
4
|
|
|
|
5
|
|
|
class StringReader implements ReaderInterface |
6
|
|
|
{ |
7
|
11 |
|
public static function read(\CsvParser\Parser $parser, $string) |
8
|
|
|
{ |
9
|
11 |
|
$data = array(); |
10
|
|
|
|
11
|
|
|
// shorten some vars for use later |
12
|
11 |
|
$d = $parser->fieldDelimiter; |
13
|
11 |
|
$e = $parser->fieldEnclosure; |
14
|
11 |
|
$l = $parser->lineDelimiter; |
15
|
|
|
|
16
|
|
|
// get headings and body |
17
|
11 |
|
list($headings, $body) = explode($l, $string, 2); |
18
|
|
|
// format array of headings/keys |
19
|
11 |
|
$headings = str_getcsv($headings, $d, $e); |
20
|
11 |
|
$numDelims = count($headings) -1; // number of field delims to find per line |
21
|
|
|
|
22
|
|
|
// tricky bit of regex, optionally matching the text enclosure (ref as \2 after first match), |
23
|
|
|
// and catches any content inside this enclosure, even if that would be the field or line delim |
24
|
|
|
// then repeating this match followed by the field delim for the number of columns we need (minus 1) and then the match again this time without the field delim |
25
|
|
|
// then splits the lines only when not in the enclosure |
26
|
11 |
|
preg_match_all('/(('. $e .')?[\s\S]*?\2?'. $d .'){'. $numDelims .'}\2?[\s\S]*?\2?('. $l .'|$)/', $body, $lines); |
27
|
|
|
|
28
|
|
|
// any lines found? loop them |
29
|
11 |
|
if ( ! empty($lines) && ! empty($lines[0])) { |
30
|
11 |
|
foreach ($lines[0] as $i => $line) { |
31
|
11 |
|
if ($line==='') { |
32
|
|
|
continue; // blank line... |
33
|
|
|
} |
34
|
11 |
|
$fields = str_getcsv($line, $d, $e); |
35
|
11 |
|
$data[$i] = array(); |
36
|
|
|
// loop the headings to map to columns |
37
|
11 |
|
foreach ($headings as $j => $heading) { |
38
|
11 |
|
$field = isset($fields[$j]) ? $fields[$j] : ''; |
39
|
11 |
|
$data[$i][$heading] = $field; |
40
|
11 |
|
} |
41
|
11 |
|
} |
42
|
11 |
|
} |
43
|
|
|
|
44
|
11 |
|
return new \CsvParser\Csv($data); |
45
|
|
|
} |
46
|
|
|
} |
47
|
|
|
|