<?php
// Own namespace
-namespace CoreFramework\Filesystem\Input\Csv;
+namespace Org\Mxchange\CoreFramework\Filesystem\Input\Csv;
// Import framework stuff
-use CoreFramework\Filesystem\Text\BaseInputTextFile;
-use CoreFramework\Stream\Filesystem\CsvInputStreamer;
+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
*
*
* @return void
*/
- protected function __construct () {
+ private function __construct () {
// Call parent constructor
parent::__construct(__CLASS__);
}
/**
* Creates an instance of this File class and prepares it for usage
*
- * @param $fileName Name of the index file
+ * @param $infoInstance An instance of a SplFileInfo class
* @return $fileInstance An instance of this File class
*/
- public final static function createCsvInputFile ($fileName) {
+ public final static function createCsvInputFile (SplFileInfo $infoInstance) {
// Get a new instance
$fileInstance = new CsvInputFile();
- // Set file name
- $fileInstance->setFileName($fileName);
-
// Init this abstract file
- $fileInstance->initFile($fileName);
+ $fileInstance->initFile($infoInstance);
// Return the prepared instance
return $fileInstance;
* 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;
}
* @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;
+ $isInQuotes = false;
// Init column data
$column = '';
// "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?
- if (($isInQuotes === FALSE) && ($char == $columnSeparator)) {
- // Debug message
- //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] Adding column=%s ...', __METHOD__, __LINE__, $column));
-
+ //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('[%s:%d:] idx=%d,char=%s ...', __METHOD__, __LINE__, $idx, $char));
+ if (($isInQuotes === false) && ($char == $columnSeparator)) {
// 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
- assert(($isInQuotes === TRUE) || (empty($column)));
+ //* 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;
}