Reputation: 33
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
Reputation: 6730
The Intl library's NumberFormatter may be sufficient for you.
NOTE: You may need to install or enable the Int library extension to use NumberFormatter
class.
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
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
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
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