Skip to content

Instantly share code, notes, and snippets.

@inxilpro
Created June 4, 2024 20:32
Show Gist options
  • Save inxilpro/88713f37d374e00fc9b63b7bf4f8d85e to your computer and use it in GitHub Desktop.
Save inxilpro/88713f37d374e00fc9b63b7bf4f8d85e to your computer and use it in GitHub Desktop.
<?php
function str_inflect(string $value, Countable|int|float $count = null, bool $format = false, bool $spellout = false): string
{
preg_match('/^(?:(?<verb>is(?: an?)?|are)\s+)?(?:(?<count>\d+(?:[,.]\d+)?)\s+)?(?<value>.*)/m', $value, $matches);
// Get rid of any commas in the input value
$matches['count'] = str_replace(',', '', $matches['count']);
// This is used for pluralization, but whatever input was provided
// in $value will be used when building the final string
$count = match (true) {
is_countable($count) => count($count),
null !== $count => $count,
str_contains($matches['count'], '.') => (float) $matches['count'],
'' !== $matches['count'] => (int) $matches['count'],
default => throw new InvalidArgumentException('You must provide a count to str_inflect()'),
};
$formatted = match (true) {
$spellout && $format => throw new InvalidArgumentException('You cannot use both `format` and `spellout` when calling str_inflect()'),
$format => Number::format($count),
$spellout => Number::spell($count),
default => $matches['count'],
};
$singular = (int) ceil($count) === 1;
// Allow for "is a" or "is an" cases
$is = 'are' === $matches['verb'] ? 'is' : $matches['verb'];
return str($matches['value'])
->when($singular, fn($str) => $str->singular(), fn($str) => $str->plural())
->when('' !== $matches['count'], fn($str) => $str->prepend("{$formatted} "))
->when(! empty($matches['verb']), fn($str) => $str->prepend($singular ? "{$is} " : 'are '))
->toString();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment