From 8bd14b4385ad21136ef4e1c310a005ad13e5c57c Mon Sep 17 00:00:00 2001 From: Clemens Schwaighofer Date: Wed, 14 Jan 2026 10:42:16 +0900 Subject: [PATCH] Add parseCharacterRanges function to Strings.php and tests --- src/Convert/Strings.php | 45 +++++++++++ src/Create/RandomKey.php | 10 +-- .../Convert/CoreLibsConvertStringsTest.php | 78 +++++++++++++++++++ 3 files changed, 128 insertions(+), 5 deletions(-) diff --git a/src/Convert/Strings.php b/src/Convert/Strings.php index 30d4ad4..dd30b47 100644 --- a/src/Convert/Strings.php +++ b/src/Convert/Strings.php @@ -268,6 +268,51 @@ class Strings )); } + /** + * Split up character ranges in format A-Z, a-z, 0-9 + * + * @param string $input + * @return string[] + */ + public static function parseCharacterRanges(string $input): array + { + // if not alphanumeric, throw value error + if (!preg_match("/^[A-Za-z0-9\-\s]+$/u", $input)) { + throw new \InvalidArgumentException( + "The input string contains invalid characters, " + . "only alphanumeric, dash (-), space and 'or' are allowed: " + . $input + ); + } + // Remove all spaces + $input = str_replace(' ', '', $input); + $result = []; + // Find all patterns like "A-Z" (character-dash-character) + preg_match_all('/(.)-(.)/u', $input, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + $start = $match[1]; + $end = $match[2]; + // Get ASCII/Unicode values + $startOrd = ord($start[0]); + $endOrd = ord($end[0]); + // make sure start is before end + if ($startOrd > $endOrd) { + [$startOrd, $endOrd] = [$endOrd, $startOrd]; + } + + // Generate range of characters + for ($i = $startOrd; $i <= $endOrd; $i++) { + $char = chr($i); + if (!in_array($char, $result)) { + $result[] = $char; + } + } + } + // make the result unique + $result = array_unique($result); + return $result; + } + /** * Check if a regex is valid. Does not return the detail regex parser error * diff --git a/src/Create/RandomKey.php b/src/Create/RandomKey.php index 31a5c5b..7559336 100644 --- a/src/Create/RandomKey.php +++ b/src/Create/RandomKey.php @@ -27,7 +27,7 @@ class RandomKey /** @var int character count in they key character range */ private static int $key_character_range_length = 0; /** @var int default key lenghth */ - /** @deprecated Will be removed */ + /** @deprecated Will be removed, as setting has moved to randomKeyGen */ private static int $key_length = 4; /** @@ -107,7 +107,7 @@ class RandomKey * @param int $key_length key length * @return bool true for valid, false for invalid length */ - private static function validateRandomKeyLenght(int $key_length): bool + private static function validateRandomKeyLength(int $key_length): bool { if ( $key_length > 0 && @@ -125,12 +125,12 @@ class RandomKey * * @param int $key_length key length * @return bool true/false for set status - * @deprecated This function does no longer set the key length, the randomKeyGen parameter has to b used + * @deprecated This function does no longer set the key length, the randomKeyGen parameter has to be used */ public static function setRandomKeyLength(int $key_length): bool { // only if valid int key with valid length - if (self::validateRandomKeyLenght($key_length) === true) { + if (self::validateRandomKeyLength($key_length) === true) { self::$key_length = $key_length; return true; } else { @@ -176,7 +176,7 @@ class RandomKey $key_character_range_length = self::getRandomKeyDataLength(); } // if not valid key length, fallback to default - if (!self::validateRandomKeyLenght($key_length)) { + if (!self::validateRandomKeyLength($key_length)) { $key_length = self::KEY_LENGTH_DEFAULT; } // create random string diff --git a/test/phpunit/Convert/CoreLibsConvertStringsTest.php b/test/phpunit/Convert/CoreLibsConvertStringsTest.php index ed4bbc9..26c635e 100644 --- a/test/phpunit/Convert/CoreLibsConvertStringsTest.php +++ b/test/phpunit/Convert/CoreLibsConvertStringsTest.php @@ -698,6 +698,84 @@ final class CoreLibsConvertStringsTest extends TestCase 'Cannot match last preg error string' ); } + + + /** + * Undocumented function + * + * @return array + */ + public function parseCharacterRangesProvider(): array + { + return [ + 'simple a-z' => [ + ['a-z'], + implode('', range('a', 'z')), + null, + ], + 'simple A-Z' => [ + ['A-Z'], + implode('', range('A', 'Z')), + null, + ], + 'simple 0-9' => [ + ['0-9'], + implode('', range('0', '9')), + null, + ], + 'mixed ranges' => [ + ['a-c', 'X-Z', '3-5'], + 'abcXYZ345', + null, + ], + 'reverse ranges' => [ + ['z-a'], + 'abcdefghijklmnopqrstuvwxyz', + null, + ], + 'overlapping ranges' => [ + ['a-f', 'd-j'], + 'abcdefghij', + null, + ], + 'mixed valid and overlap ranges' => [ + ['a-f', 'z-a', '0-3'], + 'abcdefghijklmnopqrstuvwxyz0123', + null, + ], + 'invalid ranges' => [ + ['a-あ', 'A-あ', '0-あ'], + '', + \InvalidArgumentException::class, + ], + ]; + } + + /** + * Undocumented function + * + * @covers ::parseCharacterRanges + * @dataProvider parseCharacterRangesProvider + * @testdox parseCharacterRanges $input to $expected [$_dataName] + * + * @param array $input + * @param string $expected + * @param string|null $expected_exception + * @return void + */ + public function testParseCharacterRanges( + array $input, + string $expected, + ?string $expected_exception + ): void { + if ($expected_exception !== null) { + $this->expectException($expected_exception); + } + $this->assertEquals( + $expected, + implode('', \CoreLibs\Convert\Strings::parseCharacterRanges(implode('', $input))) + ); + } } // __END__