Nathan
Nathan

Reputation: 33

PHP: Validate a given string is a valid number

I am trying to write a function that validates whether or not a given string is a valid number. I know I can use PHP is_numeric(), but the requirements is that the function needs to recognize commas as valid when:

For instance: It should recognize: 1,000,230 not ,021,201 or 1,023,12 It should also recognize positive and negative and dollar sign in front of it.

I am thinking to use preg_match to check the number format but I am not familiar with preg_match. Can you help me with this ? Any tip is appreciated ! Thank you !

Upvotes: 2

Views: 1361

Answers (4)

steven7mwesigwa
steven7mwesigwa

Reputation: 6730

The Intl library's NumberFormatter may be sufficient for you.

The NumberFormatter class

NumberFormatter::parse

NOTE: You may need to install or enable the Int library extension to use NumberFormatter class.

  • To enable the extension, check your php.ini file(C:\xampp\php\php.ini) and search for extension=intl. Remove the prepended ; if it exists. Restart Apache server and give it a try.

This extension is bundled with PHP as of PHP version 5.3.0.

/**
 * Parse a number.
 *
 * @param string $locale - The locale of the formatted number.
 * @param string $number - Formatted number.
 * @return mixed - The value of the parsed number or FALSE on error.
 */
function parse_number(string $number, $locale)
{
    return (new NumberFormatter($locale, NumberFormatter::DECIMAL))
        ->parse(trim($number));
}

echo parse_number('4.678.567.345,3827', 'de_DE'); // 4678567345.3827
echo parse_number('4.678567.345,3827', 'de_DE'); // FALSE

echo parse_number('4,678,567,345.3827', 'en_US'); // 4678567345.3827
echo parse_number(',678567,345.3827', 'en_US'); // FALSE

Upvotes: 1

Casimir et Hippolyte
Casimir et Hippolyte

Reputation: 89639

I will write it like this:

if (preg_match('~\A(?>[1-9][0-9]{0,2}(?:,[0-9]{3})*|0)(?:\.[0-9]+)?\z~', $number)) {
    // true
} else {
    // false
}

details:

~ # my favourite pattern delimiter
\A # start of the string
(?>  # group for integer part:
     # I made it atomic to fail faster when there aren't exactly 3 digits
     # between commas
    [1-9] [0-9]{0,2} # beginning doesn't start with a zero
    (?:,[0-9]{3})*   # zero or more 3 digits groups
  |                  # OR
    0                # zero alone
)
(?:  # optional group for decimals
    \.[0-9]+ # at least 1 digit
)?
\z # end of the string
~

Note that I have chosen to not allow numbers with a leading zero like 012, numbers without an integer part like .12 or integers with a dot like 12. but feel free to edit the pattern if it isn't what you want.

Upvotes: 0

trincot
trincot

Reputation: 351384

You could use this function:

function hasNumericFormat($str) {
    return preg_match("/^[-+]?[$]?([1-9]\d{0,2}(,\d{3})*|0)(\.\d+)?$/", $str);
}

Test code:

function test($str) {
    if (hasNumericFormat($str)) {
        echo "$str is OK<br>";
    } else {
        echo "$str violates numerical format<br>";
    }
}

test("-$1,234,567.89"); // ok
test(",123,567.89"); // not ok: digit missing before comma
test("1,123,56"); // not ok: not 3 digits in last group
test("-0,123,567"); // not ok: first digit is zero
test("+0"); // ok

See it run on eval.in

Upvotes: 1

Alex Howansky
Alex Howansky

Reputation: 53646

No regex needed. Strip commas, then reformat with number_format. If that matches your original input, you're good.

if (number_format(str_replace(',', '', $number)) === $number) {
   // pass
}

You can adjust how you want to handle decimals by providing a second argument to number_format().

Upvotes: 2

Related Questions