From 1e4e068121a77f993d53519790db58fbb73b723e Mon Sep 17 00:00:00 2001 From: Inhere Date: Thu, 4 Nov 2021 13:29:31 +0800 Subject: [PATCH] enhance: ini string parse, add more tests --- app/Lib/Parser/IniParser.php | 90 +++++++++++++------ ...{BaseTestCase.php => BaseKiteTestCase.php} | 2 +- test/unittest/Lib/Parser/IniParserTest.php | 74 +++++++++++++++ 3 files changed, 138 insertions(+), 28 deletions(-) rename test/unittest/{BaseTestCase.php => BaseKiteTestCase.php} (76%) create mode 100644 test/unittest/Lib/Parser/IniParserTest.php diff --git a/app/Lib/Parser/IniParser.php b/app/Lib/Parser/IniParser.php index 1a67876..edd6fc6 100644 --- a/app/Lib/Parser/IniParser.php +++ b/app/Lib/Parser/IniParser.php @@ -4,14 +4,18 @@ use Toolkit\Stdlib\Str; use function explode; +use function is_array; use function is_numeric; +use function is_string; use function ltrim; use function preg_match; use function rtrim; use function str_ends_with; +use function str_starts_with; use function strlen; use function substr; use function trim; +use function vdump; /** * class IniParser @@ -34,7 +38,7 @@ public static function parseString(string $str): array * - ignores commented lines that start with ";" or "#" * - ignores broken lines that do not have "=" * - supports array values and array value keys - * - supports inline array value + * - enhance: supports inline array value * * @param string $str * @@ -52,16 +56,19 @@ public function parse(string $str): array $sectionName = ''; foreach ($lines as $line) { - $line = trim($line); + // empty line + if (!$line = trim($line)) { + continue; + } - // empty or comments line - if (!$line || $line[0] === "#" || $line[0] === ";") { + // comments line + if ($line[0] === "#" || $line[0] === ";" || str_starts_with($line, '//')) { continue; } // section line. eg: [arrayName] - if ($line[0] === '[' && $endIdx = strpos($line, ']')) { - $sectionName = substr($line, 1, $endIdx - 1); + if (strlen($line) > 3 && $line[0] === '[' && str_ends_with($line, ']')) { + $sectionName = substr($line, 1, -1); continue; } @@ -76,45 +83,68 @@ public function parse(string $str): array // inline array value. eg: tags=[abc, 234] if ($val && $val[0] === '[' && str_ends_with($val, ']')) { - $val = Str::splitTrimmed(substr($val, 1, - 1)); + $val = Str::toTypedArray(substr($val, 1, - 1)); + } + + // top field + if (!$sectionName) { + $ret[$key] = $val; + continue; } // in section. eg: [arrayName] -> $sectionName='arrayName' - if ($sectionName) { - // remove quote chars - if (preg_match("/^\".*\"$/", $val) || preg_match("/^'.*'$/", $val)) { - $val = mb_substr($val, 1, -1); - } - // is array. - // eg: val_arr[] = "arr_elem_one" - // eg: val_arr_two[some_key] = "some_key_value" - // $t = preg_match("^\[(.*?)\]^", $key, $matches); - $ok = preg_match("^\[(.*?)]^", $key, $matches); - if ($ok === 1 && isset($matches[0])) { - // $arr_name = preg_replace('#\[(.*?)\]#is', '', $key); - [$arrName, $subKey] = explode('[', trim($key, ']')); + // remove quote chars + if ( + is_string($val) && + (preg_match("/^\".*\"$/", $val) || preg_match("/^'.*'$/", $val)) + ) { + $val = mb_substr($val, 1, -1); + } + + // is array sub key. + // eg: + // [] = "arr_elem_one" + // val_arr[] = "arr_elem_one" + // val_arr_two[some_key] = "some_key_value" + $ok = preg_match("/[\w-]{0,64}\[(.*?)]$/", $key, $matches); + if ($ok === 1 && isset($matches[0])) { + [$arrName, $subKey] = explode('[', trim($key, ']')); + if ($arrName !== '') { if (!isset($ret[$sectionName][$arrName]) || !is_array($ret[$sectionName][$arrName])) { $ret[$sectionName][$arrName] = []; } - if ($subKey !== '') { + if ($subKey !== '') { // eg: val_arr[subKey] = "arr_elem_one" $ret[$sectionName][$arrName][$subKey] = $val; } else { // eg: val_arr[] = "arr_elem_one" $ret[$sectionName][$arrName][] = $val; } } else { - $ret[$sectionName][$key] = $val; + if (!isset($ret[$sectionName]) || !is_array($ret[$sectionName])) { + $ret[$sectionName] = []; + } + + if ($subKey !== '') { // eg: [subKey] = "arr_elem_one" + $ret[$sectionName][$subKey] = $val; + } else { // eg: [] = "arr_elem_one" + $ret[$sectionName][] = $val; + } } } else { - $ret[$key] = $val; + $ret[$sectionName][$key] = $val; } } return $ret; } + /** + * @param string $str + * + * @return string + */ protected function removeQuotes(string $str): string { if (preg_match("/^\".*\"$/", $str) || preg_match("/^'.*'$/", $str)) { @@ -124,16 +154,22 @@ protected function removeQuotes(string $str): string return $str; } - protected function str2array(string $str): array + /** + * @param string $str + * + * @return array + */ + protected function str2typedList(string $str): array { + $str = substr($str, 1, - 1); if (!$str) { return []; } - $arr = Str::splitTrimmed(substr($str, 1, - 1)); - foreach ($arr as $val) { + $arr = Str::splitTrimFiltered($str); + foreach ($arr as &$val) { if (is_numeric($val) && strlen($val) < 11) { - + $val = (int)$val; } } diff --git a/test/unittest/BaseTestCase.php b/test/unittest/BaseKiteTestCase.php similarity index 76% rename from test/unittest/BaseTestCase.php rename to test/unittest/BaseKiteTestCase.php index b7abee2..a9e66bc 100644 --- a/test/unittest/BaseTestCase.php +++ b/test/unittest/BaseKiteTestCase.php @@ -9,7 +9,7 @@ * * @package Inhere\KiteTest */ -abstract class BaseTestCase extends TestCase +abstract class BaseKiteTestCase extends TestCase { } diff --git a/test/unittest/Lib/Parser/IniParserTest.php b/test/unittest/Lib/Parser/IniParserTest.php new file mode 100644 index 0000000..c20167e --- /dev/null +++ b/test/unittest/Lib/Parser/IniParserTest.php @@ -0,0 +1,74 @@ +assertNotEmpty($data); + $this->assertArrayHasKey('inlineArr', $data); + $this->assertEquals(['ab', 23, 34.5], $data['inlineArr']); + + $this->assertArrayHasKey('simpleList', $data); + $this->assertEquals([567, 'some value'], $data['simpleList']); + + $this->assertArrayHasKey('simpleMap', $data); + $this->assertEquals(['val_one' => 567, 'val_two' => 'some value'], $data['simpleMap']); + } + + public function testParseIni_1levelList(): void + { + $ini = ' +# simple list array +[simpleList] +[] = 567 +[] = "some value" +'; + $data = IniParser::parseString($ini); + vdump($data); + $this->assertNotEmpty($data); + $this->assertArrayHasKey('simpleList', $data); + $this->assertEquals([567, 'some value'], $data['simpleList']); + } +}