diff --git a/src/AbstractCsv.php b/src/AbstractCsv.php index 1513cfd0..a5b6399d 100644 --- a/src/AbstractCsv.php +++ b/src/AbstractCsv.php @@ -215,34 +215,43 @@ public function getDelimiter() * Detect the CSV file delimiter * * @param integer $nbRows - * @param array $additionals additional delimiters + * @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 $additionals = []) + 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'); } - $additionals = array_filter($additionals, function ($str) { + $delimiters = array_filter($delimiters, function ($str) { return 1 == mb_strlen($str); }); - $delimiters = [',', ';', "\t"]; - $delim = array_unique(array_merge($delimiters, $additionals)); - $iterator = new CallbackFilterIterator(new LimitIterator($this->csv, 0, $nbRows), function ($row) { - return is_array($row) && count($row) > 1; - }); - $origDelimiter = $this->getDelimiter(); - $res = array_fill_keys($delimiters, null); + $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); + $iterator->setCsvControl($delim, $this->enclosure, $this->escape); $res[$delim] = count(iterator_to_array($iterator, false)); } - $this->setDelimiter($origDelimiter); arsort($res, SORT_NUMERIC); - - return array_keys(array_filter($res)); + $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).'`'); } /** diff --git a/test/CsvTest.php b/test/CsvTest.php index 57ef07be..e6943e03 100644 --- a/test/CsvTest.php +++ b/test/CsvTest.php @@ -84,23 +84,43 @@ public function testDelimeter() $this->csv->setDelimiter('foo'); } + public function testDetectDelimiter() + { + $this->assertSame($this->csv->detectDelimiter(), ','); + } + /** * @expectedException InvalidArgumentException */ - public function testDetectDelimiter() + public function testDetectDelimiterWithInvalidRowLimit() { - $this->assertSame($this->csv->detectDelimiter(), [',']); + $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->insertOne(['toto', 'tata', 'tutu']); - $csv->insertOne(['toto', 'tata', 'tutu']); - $csv->insertOne(['toto', 'tata', 'tutu']); - - $this->assertSame($csv->detectDelimiter(5, ['toto', '|']), [',', ';']); - $csv->detectDelimiter(-4); + $csv->setDelimiter('|'); + $csv->insertAll([ + ['toto', 'tata', 'tutu'], + ['toto', 'tata', 'tutu'], + ['toto', 'tata', 'tutu'] + ]); + + $csv->detectDelimiter(5, ['toto', '|']); } /**