Continued:
[core.git] / framework / main / classes / file_directories / text / input / csv / class_CsvInputFile.php
index efd42eb1159e27309049738974cfacf065348b22..c34a6d18fba5398425ca3e7d96f78659c341d8e7 100644 (file)
@@ -4,17 +4,20 @@ namespace Org\Mxchange\CoreFramework\Filesystem\Input\Csv;
 
 // Import framework stuff
 use Org\Mxchange\CoreFramework\Filesystem\Text\BaseInputTextFile;
+use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
 use Org\Mxchange\CoreFramework\Stream\Filesystem\CsvInputStreamer;
 
 // Import SPL stuff
+use \InvalidArgumentException;
 use \SplFileInfo;
+use \UnexpectedValueException;
 
 /**
  * A CSV file input class for writing CSV files
  *
  * @author             Roland Haeder <webmaster@ship-simu.org>
  * @version            0.0.0
- * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
+ * @copyright  Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
  * @license            GNU GPL 3.0 or any newer version
  * @link               http://www.ship-simu.org
  *
@@ -37,7 +40,7 @@ class CsvInputFile extends BaseInputTextFile implements CsvInputStreamer {
         *
         * @return      void
         */
-       protected function __construct () {
+       private function __construct () {
                // Call parent constructor
                parent::__construct(__CLASS__);
        }
@@ -65,25 +68,45 @@ class CsvInputFile extends BaseInputTextFile implements CsvInputStreamer {
         * column separators will be parsed or they may be interpreted incorrectly.
         *
         * @param       $columnSeparator        Character to use separting columns
+        * @param       $expectedMatches        Expected matches, 0 is default and means flexible
         * @return      $lineArray                      An indexed array with the read line
+        * @throws      InvalidArgumentException        If a parameter is invalid
+        * @throws      UnexpectedValueException        If the array count is not matching expected count
         */
-       public function readCsvFileLine ($columnSeparator) {
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] columnSeparator=%s - CALLED!', __METHOD__, __LINE__, $columnSeparator));
-
-               // Read raw line
-               $data = $this->getPointerInstance()->readLine();
-
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] data()=%d', __METHOD__, __LINE__, strlen($data)));
+       public function readCsvFileLine (string $columnSeparator, int $expectedMatches = 0) {
+               // Validate parameter
+               /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] columnSeparator=%s,expectedMatches=%d - CALLED!', __METHOD__, __LINE__, $columnSeparator, $expectedMatches));
+               if (strlen($columnSeparator) === 0) {
+                       // No empty column separator
+                       throw new InvalidArgumentException('Parameter "columnSeparator" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
+               } elseif ($expectedMatches < 0) {
+                       // Below zero is not valid
+                       throw new InvalidArgumentException(sprintf('expectedMatches=%d is below zero', $expectedMatches));
+               }
+
+               // Read raw line and trim anything unwanted away
+               $data = trim($this->getPointerInstance()->readLine());
+
+               // Is the line empty?
+               /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] data(%d)=%s', __METHOD__, __LINE__, strlen($data), $data));
+               if (empty($data)) {
+                       // Yes, then skip below code
+                       /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Read data is an empty line - EXIT!', __METHOD__, __LINE__));
+                       return;
+               }
 
                // Parse data
                $lineArray = $this->parseDataToIndexedArray($data, $columnSeparator);
 
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
+               // Is the expected count found?
+               /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] expectedMatches=%d,lineArray()=%d', __METHOD__, __LINE__, $expectedMatches, count($lineArray)));
+               if (($expectedMatches > 0) && (count($lineArray) !== $expectedMatches)) {
+                       // Invalid line found as strict count matching is requested
+                       throw new UnexpectedValueException(sprintf('lineArray()=%d has not expected count %d', count($lineArray), $expectedMatches), FrameworkInterface::EXCEPTION_UNEXPECTED_VALUE);
+               }
 
                // Return it
+               /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
                return $lineArray;
        }
 
@@ -94,12 +117,10 @@ class CsvInputFile extends BaseInputTextFile implements CsvInputStreamer {
         * @param       $columnSeparator        Character to use separting columns
         * @return      $lineArray                      An indexed array with the read line
         */
-       private function parseDataToIndexedArray ($data, $columnSeparator) {
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] data()=%d,columnSeparator=%s - CALLED!', __METHOD__, __LINE__, strlen($data), $columnSeparator));
-
+       private function parseDataToIndexedArray (string $data, string $columnSeparator) {
                // Init return array
-               $lineArray = array();
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] data()=%d,columnSeparator=%s - CALLED!', __METHOD__, __LINE__, strlen($data), $columnSeparator));
+               $lineArray = [];
 
                // Whether the parser reads a quoted string (which may contain the column separator again)
                $isInQuotes = false;
@@ -112,65 +133,49 @@ class CsvInputFile extends BaseInputTextFile implements CsvInputStreamer {
                        // "Cache" char
                        $char = substr($data, $idx, 1);
 
-                       // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] idx=%s,char=%s ...', __METHOD__, __LINE__, $idx, $char));
-
                        // Is the column separator found and not within quotes?
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] idx=%d,char=%s ...', __METHOD__, __LINE__, $idx, $char));
                        if (($isInQuotes === false) && ($char == $columnSeparator)) {
-                               // Debug message
-                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
-
                                // Add this line to the array
+                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
                                array_push($lineArray, $column);
 
-                               // Debug message
-                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
-
                                // Clear variable ...
+                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] line[]=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
                                $column = '';
 
                                // ... and skip it
                                continue;
                        } elseif ($char == chr(34)) {
-                               // Debug message
-                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] column=%s ...', __METHOD__, __LINE__, $column));
-
                                // $column must be empty at this point if we are at starting quote
+                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] column=%s ...', __METHOD__, __LINE__, $column));
                                assert(($isInQuotes === true) || (empty($column)));
 
                                // Double-quote found, so flip variable
                                $isInQuotes = (!$isInQuotes);
 
-                               // Debug message
-                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] isInQuotes=%d ...', __METHOD__, __LINE__, intval($isInQuotes)));
-
                                // Skip double-quote (escaping of them is not yet supported)
+                               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] isInQuotes=%d ...', __METHOD__, __LINE__, intval($isInQuotes)));
                                continue;
                        }
 
-                       // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding char=%s ...', __METHOD__, __LINE__, $idx, $char));
-
                        // Add char to column
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding char=%s ...', __METHOD__, __LINE__, $idx, $char));
                        $column .= $char;
-               } // END - for
+               }
 
                // Is there something outstanding?
                if (!empty($column)) {
-                       // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
-
                        // Then don't forget this. :-)
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
                        array_push($lineArray, $column);
 
                        // Debug message
-                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
-               } // END - if
-
-               // Debug message
-               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] lineArray()=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
+                       //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] line[]=%d - After add!', __METHOD__, __LINE__, count($lineArray)));
+               }
 
                // Return it
+               //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] line[]=%d - EXIT!', __METHOD__, __LINE__, count($lineArray)));
                return $lineArray;
        }