diff options
author | ignace nyamagana butera <nyamsprod@gmail.com> | 2014-03-11 09:29:52 +0100 |
---|---|---|
committer | ignace nyamagana butera <nyamsprod@gmail.com> | 2014-03-11 09:29:52 +0100 |
commit | 4610efac7e2a467971b7be7dc546072d84cf166f (patch) | |
tree | f12e88ae7d1c452d6aa9c343729460bbd1f42780 | |
parent | 94c80b7c9eba98b8c7f0755c25185df6474fd717 (diff) | |
parent | ce37e2651acb031b4e914c9cec7acf522524d806 (diff) | |
download | csv-4610efac7e2a467971b7be7dc546072d84cf166f.zip csv-4610efac7e2a467971b7be7dc546072d84cf166f.tar.gz csv-4610efac7e2a467971b7be7dc546072d84cf166f.tar.bz2 |
Merge pull request #25 from thephpleague/detectdelimiter
adding detectDelimiter to AbstractCsv class #16
-rw-r--r-- | src/AbstractCsv.php | 45 | ||||
-rw-r--r-- | test/CsvTest.php | 39 |
2 files changed, 84 insertions, 0 deletions
diff --git a/src/AbstractCsv.php b/src/AbstractCsv.php index 4d92418..a5b6399 100644 --- a/src/AbstractCsv.php +++ b/src/AbstractCsv.php @@ -39,6 +39,8 @@ use SplFileInfo; use SplFileObject; use SplTempFileObject; use InvalidArgumentException; +use LimitIterator; +use CallbackFilterIterator; /** * A abstract class to enable basic CSV manipulation @@ -210,6 +212,49 @@ class AbstractCsv implements JsonSerializable, IteratorAggregate } /** + * Detect the CSV file delimiter + * + * @param integer $nbRows + * @param array $delimiters additional delimiters + * + * @return string + * + * @throws \InvalidArgumentException If $nbRows value is invalid + * @throws \RuntimeException If too many delimiters are found + */ + public function detectDelimiter($nbRows = 1, array $delimiters = []) + { + $nbRows = filter_var($nbRows, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]); + if (! $nbRows) { + throw new InvalidArgumentException('`$nbRows` must be a valid positive integer'); + } + $delimiters = array_filter($delimiters, function ($str) { + return 1 == mb_strlen($str); + }); + $delimiters = array_merge([',', ';', "\t"], $delimiters); + $delimiters = array_unique($delimiters); + $iterator = new CallbackFilterIterator( + new LimitIterator($this->csv, 0, $nbRows), + function ($row) { + return is_array($row) && count($row) > 1; + } + ); + $res = []; + foreach ($delimiters as $delim) { + $iterator->setCsvControl($delim, $this->enclosure, $this->escape); + $res[$delim] = count(iterator_to_array($iterator, false)); + } + arsort($res, SORT_NUMERIC); + $res = array_keys(array_filter($res)); + if (! $res) { + return null; + } elseif (count($res) == 1) { + return $res[0]; + } + throw new RuntimeException('too many delimiters were found: `'.implode('`,`', $res).'`'); + } + + /** * set the field enclosure * * @param string $enclosure diff --git a/test/CsvTest.php b/test/CsvTest.php index c810cbc..ea822a2 100644 --- a/test/CsvTest.php +++ b/test/CsvTest.php @@ -85,6 +85,45 @@ class CsvTest extends PHPUnit_Framework_TestCase $this->csv->setDelimiter('foo'); } + public function testDetectDelimiter() + { + $this->assertSame($this->csv->detectDelimiter(), ','); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testDetectDelimiterWithInvalidRowLimit() + { + $this->csv->detectDelimiter(-4); + } + + public function testDetectDelimiterWithNoCSV() + { + $file = new SplTempFileObject; + $file->fwrite("How are you today ?\nI'm doing fine thanks!"); + $csv = new Writer($file); + $this->assertNull($csv->detectDelimiter(5, ['toto', '|'])); + } + + /** + * @expectedException RuntimeException + */ + public function testDetectDelimiterWithInconsistentCSV() + { + $csv = new Writer(new SplTempFileObject); + $csv->setDelimiter(';'); + $csv->insertOne(['toto', 'tata', 'tutu']); + $csv->setDelimiter('|'); + $csv->insertAll([ + ['toto', 'tata', 'tutu'], + ['toto', 'tata', 'tutu'], + ['toto', 'tata', 'tutu'] + ]); + + $csv->detectDelimiter(5, ['toto', '|']); + } + /** * @expectedException InvalidArgumentException */ |