summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorignace nyamagana butera <nyamsprod@gmail.com>2014-03-11 09:29:52 +0100
committerignace nyamagana butera <nyamsprod@gmail.com>2014-03-11 09:29:52 +0100
commit4610efac7e2a467971b7be7dc546072d84cf166f (patch)
treef12e88ae7d1c452d6aa9c343729460bbd1f42780
parent94c80b7c9eba98b8c7f0755c25185df6474fd717 (diff)
parentce37e2651acb031b4e914c9cec7acf522524d806 (diff)
downloadcsv-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.php45
-rw-r--r--test/CsvTest.php39
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
*/