bryan
bryan

Reputation: 9369

Parse a number but keep negative's

I am trying to un-format a number to it's original form but keep whether or not it is negative. Someone on stack overflow led me to this code that work's very nicely but it does not keep the negative.

Could anyone help me get a better fix on this?

EDIT - For USD Currency/normal numbers

Example:

1,234 = 1234

-1,234 = -1234

1,234.00 = 1234

1,234.56 = 1234.56

function numberUnformat($number)
{
   $cleanString = preg_replace('/([^0-9\.,])/i', '', $number);
   $onlyNumbersString = preg_replace('/([^0-9])/i', '', $number);

   $separatorsCountToBeErased = strlen($cleanString) - strlen($onlyNumbersString) - 1;

   $stringWithCommaOrDot = preg_replace('/([,\.])/', '', $cleanString, $separatorsCountToBeErased);
   $removedThousendSeparator = preg_replace('/(\.|,)(?=[0-9]{3,}$)/', '', $stringWithCommaOrDot);

   return (float) str_replace(',', '.', $removedThousendSeparator);
}

Upvotes: 5

Views: 3483

Answers (6)

Mike Brant
Mike Brant

Reputation: 71384

I would actually add some parameters to the function to allow specification of grouping and decimal separators (and possibly allow ability to cast to float or decimal and go to a solution like this:

function number_unformat($num_string, $group_sep = ',', $dec_sep = '.', $cast_to_type = true) {
    if (substr_count($num_string, $dec_sep) > 1) {
        // input was invalid
        throw new Exception('Inavlid string: `' . $num_string . '` passed to function. Too many decimal separators.');
    }   
    // remove grouping separator
    $string = str_replace($group_sep, '', $num_string);
    if (true === $cast_to_type) {
        // change any decimal separators to periods before casting
        $string = str_replace($dec_sep, '.', $string, $count);
        if ($count === 1) {
            return (float)$string;
        } else {
            return (int)$string;
        }
    } else {
        return $string;
    }
}

Note that there is no need at all to use regular expression here.

Upvotes: 2

Andreas Baumgart
Andreas Baumgart

Reputation: 2747

In case you have the ICU extension (which is bundled in PHP 5.3) available, try this:

$formatter = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
echo $formatter->parse('-1,234.56');

Upvotes: 6

Mark Reed
Mark Reed

Reputation: 95242

If you want to remove any extraneous minus signs in the middle of the string, too:

$cleanString = preg_replace('/[^0-9.,-]|(?<=.)-/', '', $number);
$onlyNumbersString = preg_replace('/[^0-9-]|(?<=.)-/', '', $number);

Note that you don't need the parentheses, backslash, or /i in your original.

Upvotes: 2

anon
anon

Reputation:

Change your regular expression to match the negative numbers, too:

$cleanString = preg_replace('/([^\-0-9\.,])/i', '', $number);

Test cases:

echo numberUnformat('1,234')."\n";
echo numberUnformat('-1,234')."\n";
echo numberUnformat('1,234.00')."\n";
echo numberUnformat('1,234.56 ')."\n";

Output:

1234
-1234
1234
1234.56

Demo!

Upvotes: 2

Jud
Jud

Reputation: 1188

One could muck with the regular expressions to keep the negative, but to me it's simpler to do the following at the end:

$absvalue = (float) str_replace(',', '.', $removedThousendSeparator);
if ($number[0] == '-') {
    $absvalue = $absvalue * -1.0;
}
return $absvalue;

I might have a syntax error in there, my PHP is rusty, but the idea is just to check and see if the input string starts with a negative sign, and if it does, multiply the result by negative 1.

Upvotes: 0

AlliterativeAlice
AlliterativeAlice

Reputation: 12577

A fairly quick (though imperfect) fix would be to change the first two lines of the function:

$cleanString = preg_replace('/([^-0-9\.,])/i', '', $number);
$onlyNumbersString = preg_replace('/([^-0-9])/i', '', $number);

Though this will cause a problem if you have a number like 2-434.43.

Upvotes: 0

Related Questions