X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=framework%2Fmain%2Fclasses%2Ffile_directories%2Ftext%2Finput%2Fcsv%2Fclass_CsvInputFile.php;h=c34a6d18fba5398425ca3e7d96f78659c341d8e7;hb=refs%2Fheads%2Fmaster;hp=1623815d6756a45417ad9f40561326bb6af62603;hpb=f57dd51863ec9baacba447d76b46d5c709b9b02e;p=core.git diff --git a/framework/main/classes/file_directories/text/input/csv/class_CsvInputFile.php b/framework/main/classes/file_directories/text/input/csv/class_CsvInputFile.php index 1623815d..c34a6d18 100644 --- a/framework/main/classes/file_directories/text/input/csv/class_CsvInputFile.php +++ b/framework/main/classes/file_directories/text/input/csv/class_CsvInputFile.php @@ -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 * @version 0.0.0 - * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2019 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; }