Skip to content

Commit

Permalink
Add str_increment and str_decrement functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Fan2Shrek committed Oct 16, 2023
1 parent 4051889 commit 9b5adbf
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 3 deletions.
119 changes: 116 additions & 3 deletions src/Php83/Php83.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

/**
* @author Ion Bazan <ion.bazan@gmail.com>
* @author Pierre Ambroise <pierre27.ambroise@gmail.com>
*
* @internal
*/
Expand Down Expand Up @@ -72,14 +73,126 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin

switch ($pad_type) {
case \STR_PAD_LEFT:
return mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string;
return mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding) . $string;
case \STR_PAD_RIGHT:
return $string.mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
return $string . mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding);
default:
$leftPaddingLength = floor($paddingRequired / 2);
$rightPaddingLength = $paddingRequired - $leftPaddingLength;

return mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
return mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding) . $string . mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding);
}
}

public static function str_increment(string $string): string
{
if ('' === $string) {
throw new \ValueError('str_increment(): Argument #1 ($string) cannot be empty');
}

if (!\ctype_alnum($string)) {
throw new \ValueError('str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');
}

if (\is_numeric($string)) {
$offset = stripos($string, 'e');
if ($offset !== false) {
$char = $string[$offset];
$char++;
$string[$offset] = $char;
$string++;

switch ($string[$offset]) {
case 'f':
$string[$offset] = 'e';
break;
case 'F':
$string[$offset] = 'E';
break;
case 'g':
$string[$offset] = 'f';
break;
case 'G':
$string[$offset] = 'F';
break;
}

return $string;
}
}

return ++$string;
}

public static function str_decrement(string $string): string
{
if ('' === $string) {
throw new \ValueError('str_decrement(): Argument #1 ($string) cannot be empty');
}

if (!\ctype_alnum($string)) {
throw new \ValueError('str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters');
}

if (\preg_match('/^0[aA]?$|^[aA]$/', $string)) {
throw new \ValueError(sprintf('str_decrement(): Argument #1 ($string) "%s" is out of decrement range', $string));
}

if (!\in_array(substr($string, -1), ['A', 'a', '0'], true)) {
return join('', array_slice(str_split($string), 0, -1)) . chr(ord(substr($string, -1)) - 1);
}

$toConvert = strrev($string);
$carry = '';
$decremented = '';

for ($i = 0; $i < strlen($toConvert); $i++) {
$char = $toConvert[$i];

switch ($char) {
case 'A':
if ('' !== $carry) {
$decremented .= $carry;
$carry = '';
}
$carry = 'Z';

break;
case 'a':
if ('' !== $carry) {
$decremented .= $carry;
$carry = '';
}
$carry = 'z';

break;
case '0':
if ('' !== $carry) {
$decremented .= $carry;
$carry = '';
}
$carry = '9';

break;
case '1':
if ('' !== $carry) {
$decremented .= $carry;
$carry = '';
}

break;
default:
if ('' !== $carry) {
$decremented .= $carry;
$carry = '';
}

if (!\in_array($char, ['A', 'a', '0'], true)) {
$decremented .= chr(ord($char) - 1);
}
}
}

return strrev($decremented);
}
}
8 changes: 8 additions & 0 deletions src/Php83/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $
function stream_context_set_options($context, array $options): bool { return stream_context_set_option($context, $options); }
}

if (!function_exists('str_increment')) {
function str_increment(string $string): string { return p\Php83::str_increment($string); }
}

if (!function_exists('str_decrement')) {
function str_decrement(string $string): string { return p\Php83::str_decrement($string); }
}

if (\PHP_VERSION_ID >= 80100) {
return require __DIR__.'/bootstrap81.php';
}
Expand Down
121 changes: 121 additions & 0 deletions tests/Php83/Php83Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,125 @@ public function testDateTimeExceptionClassesExist()
$this->assertTrue(class_exists(\DateMalformedIntervalStringException::class));
$this->assertTrue(class_exists(\DateMalformedPeriodStringException::class));
}

/**
* @covers \Symfony\Polyfill\Php83\Php83::str_increment
*
* @dataProvider strIncrementProvider
*/
public function testStrIncrement(string $result, string $string)
{
$this->assertSame($result, str_increment($string));
}

/**
* @covers \Symfony\Polyfill\Php83\Php83::str_decrement
*
* @dataProvider strDecrementProvider
*/
public function testStrDecrement(string $result, string $string)
{
$this->assertSame($result, str_decrement($string));
}

public static function strIncrementProvider(): iterable
{
yield ['ABD', 'ABC'];
yield ['EB', 'EA'];
yield ['AAA', 'ZZ'];
yield ['AAA2', 'AAA1'];
yield ['Ba', 'Az'];
yield ['bA', 'aZ'];
yield ['B0', 'A9'];
yield ['b0', 'a9'];
yield ['AAa', 'Zz'];
yield ['aaA', 'zZ'];
yield ['10a', '9z'];
yield ['10A', '9Z'];
yield ['5e7', '5e6'];
yield ['e', 'd'];
yield ['E', 'D'];
yield ['5', '4'];
}

public static function strDecrementProvider(): iterable
{
yield ['Ay', 'Az'];
yield ['aY', 'aZ'];
yield ['A8', 'A9'];
yield ['a8', 'a9'];
yield ['Yz', 'Za'];
yield ['yZ', 'zA'];
yield ['Y9', 'Z0'];
yield ['y9', 'z0'];
yield ['Z', 'aA'];
yield ['9', 'A0'];
yield ['9', 'a0'];
yield ['9', '10'];
yield ['Z', '1A'];
yield ['z', '1a'];
yield ['9z', '10a'];
yield ['5e5', '5e6'];
yield ['c', 'd'];
yield ['C', 'D'];
yield ['3', '4'];
}

/**
* @covers \Symfony\Polyfill\Php83\Php83::str_increment
*
* @dataProvider strInvalidIncrementProvider
*/
public function testInvalidStrIncrement(string $errorMessage, string $string)
{
$this->expectException(\ValueError::class);
$this->expectExceptionMessage($errorMessage);

str_increment($string);
}


public static function strInvalidIncrementProvider(): iterable
{
yield ['str_increment(): Argument #1 ($string) cannot be empty', ""];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', "-cc"];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', "Z "];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', " Z"];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', "é"];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', '我喜歡雞肉'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'α'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'ω'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'Α'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'Ω'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'foo1.txt'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', '1f.5'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', 'foo.1.txt'];
yield ['str_increment(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', '1.f.5'];
}


/**
* @covers \Symfony\Polyfill\Php83\Php83::str_decrement
*
* @dataProvider strInvalidDecrementProvider
*/
public function testInvalidStrDecrement(string $errorMessage, string $string)
{
$this->expectException(\ValueError::class);
$this->expectExceptionMessage($errorMessage);

str_decrement($string);
}

public static function strInvalidDecrementProvider(): iterable
{
yield ['str_decrement(): Argument #1 ($string) cannot be empty', ''];
yield ['str_decrement(): Argument #1 ($string) must be composed only of alphanumeric ASCII characters', '我喜歡雞肉'];
yield ['str_decrement(): Argument #1 ($string) "0" is out of decrement range', '0'];
yield ['str_decrement(): Argument #1 ($string) "a" is out of decrement range', 'a'];
yield ['str_decrement(): Argument #1 ($string) "A" is out of decrement range', 'A'];
yield ['str_decrement(): Argument #1 ($string) "00" is out of decrement range', '00'];
yield ['str_decrement(): Argument #1 ($string) "0a" is out of decrement range', '0a'];
yield ['str_decrement(): Argument #1 ($string) "0A" is out of decrement range', '0A'];
}
}

0 comments on commit 9b5adbf

Please sign in to comment.