Skip to content
Open
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ composer.phar
/phpunit.phar
/phpunit.xml
/.phpunit.cache
/.phpunit.result.cache

# PHPBench
.phpbench
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 2.7.1 under development

- no changes in this release.
- New #156: Add `NumericHelper::trimDecimalZeros()` (@samdark)

## 2.7.0 November 23, 2025

Expand Down
39 changes: 38 additions & 1 deletion src/NumericHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
}

/**
* Converts human readable size to bytes.
* Converts human-readable size to bytes.
*
* @param string $string Human readable size. Examples: `1024`, `1kB`, `1.5M`, `1GiB`. Full
* list of supported postfixes in {@see FILESYSTEM_SIZE_POSTFIXES}.
Expand Down Expand Up @@ -157,9 +157,46 @@
throw new InvalidArgumentException("Not supported postfix '$postfix' in input string: $string");
}

return (int) ((float) $numericPart * $postfixMultiplier);

Check warning on line 160 in src/NumericHelper.php

View workflow job for this annotation

GitHub Actions / mutation / PHP 8.5-ubuntu-latest

Escaped Mutant for Mutator "CastFloat": @@ @@ if ($postfixMultiplier === null) { throw new InvalidArgumentException("Not supported postfix '{$postfix}' in input string: {$string}"); } - return (int) ((float) $numericPart * $postfixMultiplier); + return (int) ($numericPart * $postfixMultiplier); } throw new InvalidArgumentException("Incorrect input string: {$string}"); }
}

throw new InvalidArgumentException("Incorrect input string: $string");
}

/**
* Trims trailing decimal zeros from a numeric string.
*
* If the fractional part consists only of zeros, the decimal dot separator is removed as well.
* The value that is `null` is returned as-is.
*
* @param string|null $value Numeric string or null.
*
* @return string|null The input string with trailing decimal zeros (and a trailing decimal
* dot separator, if any) removed, or `null` if the input was `null`.
*
* @see is_numeric()
*/
public static function trimDecimalZeros(?string $value): ?string
{
if ($value === null) {
return null;
}

if (!is_numeric($value)) {
throw new InvalidArgumentException(
sprintf('Value must be numeric string or null. "%s" given.', $value)
);
}

$value = trim($value);

if (!str_contains($value, '.')) {
return $value;
}

$value = rtrim($value, '0');
$value = rtrim($value, '.');

return $value ?: '0';
}
}
38 changes: 35 additions & 3 deletions tests/NumericHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Strings\Tests;

use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use Yiisoft\Strings\NumericHelper;
Expand Down Expand Up @@ -35,7 +36,7 @@ public function testToOrdinal(): void

public function testToOrdinalWithIncorrectType(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
NumericHelper::toOrdinal('bla-bla');
}

Expand Down Expand Up @@ -63,7 +64,7 @@ public function testNormalize(mixed $input, string $expected): void

public function testNormalizeWithIncorrectType(): void
{
$this->expectException(\InvalidArgumentException::class);
$this->expectException(InvalidArgumentException::class);
NumericHelper::normalize([]);
}

Expand Down Expand Up @@ -167,7 +168,38 @@ public static function dataConvertHumanReadableSizeToBytesWithInvalidStrings():
#[DataProvider('dataConvertHumanReadableSizeToBytesWithInvalidStrings')]
public function testConvertHumanReadableSizeToBytesWithInvalidStrings(string $string, string $message): void
{
$this->expectExceptionObject(new \InvalidArgumentException($message));
$this->expectExceptionObject(new InvalidArgumentException($message));
NumericHelper::convertHumanReadableSizeToBytes($string);
}

public static function dataTrimDecimalZeros(): array
{
return [
'no decimals in integer with zeros' => ['390', '390'],
'all zeros' => ['390.000', '390'],
'no zeros' => ['3.14', '3.14'],
'some zeros' => ['42.010', '42.01'],
'zeros' => ['0.0', '0'],
'decimal only' => ['.5', '.5'],
'decimal zero' => ['.0', '0'],
'start with zero' => ['0.25', '0.25'],
'negative' => ['-3.000', '-3'],
'null' => [null, null],
'starts with zero' => ['02471', '02471'],
'exponent' => ['1337e0', '1337e0'],
'spaces' => ['3.140 ', '3.14'],
];
}

#[DataProvider('dataTrimDecimalZeros')]
public function testTrimDecimalZeros(?string $input, ?string $expected): void
{
$this->assertSame($expected, NumericHelper::trimDecimalZeros($input));
}

public function trimDecimalZerosWithNonNumericString(): void
{
$this->expectException(InvalidArgumentException::class);
NumericHelper::trimDecimalZeros('hello');
}
}
12 changes: 12 additions & 0 deletions tests/benchmarks/NumericHelperBench.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,16 @@ public function benchNormalize(): void
NumericHelper::normalize('1,000,000.123');
NumericHelper::normalize('1 000 000,123');
}

public function benchTrimDecimalZeros(): void
{
NumericHelper::trimDecimalZeros('390');
NumericHelper::trimDecimalZeros('390.000');
NumericHelper::trimDecimalZeros('3.14');
NumericHelper::trimDecimalZeros('42.010');
NumericHelper::trimDecimalZeros('0.0');
NumericHelper::trimDecimalZeros('.5');
NumericHelper::trimDecimalZeros('0.25');
NumericHelper::trimDecimalZeros('-3.000');
}
}
Loading