Parse a number but keep negative's - php

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);
}

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');

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!

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.

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.

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.

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.

Related

PHP Regex for similarity check

Can you think of any regular expression that resolves these similarities in PHP? The idea is to get a match without considering the last letters.
<?php
$word1 = 'happyness';
$word2 = 'happys';
if (substr($word1, 0, -4) == substr($word2, 0, -1))
{
echo 'same word1';
}
$word1 = 'kisses';
$word2 = 'kiss';
if (substr($word1, 0, -2) == $word2)
{
echo 'same word2';
}
$word1 = 'consonant';
$word2 = 'consonan';
if (substr($word1, 0, -1) == $word2)
{
echo 'same word3';
}
By putting the words together like happys happyness and capturing as many word characters from word 1 as word 2 matches. See this demo at regex101. Use it with the i flag for casless matching.
^(\w+)\w* \1
To use this in PHP with preg_match see this PHP demo at tio.run
preg_match('/^(\w+)\w* \1/i', preg_quote($word1,'/')." ".preg_quote($word2,'/'), $out);
where $out[1] holds the captures or $out would be an empty array if there wasn't a match.
You could use a small helper function, the first function just matches up to the length of the second string, so doesn't care how many characters it truncates. The main code works similar to your code except it uses the length of the second value as the length of the substring to take...
function match( string $a, string $b ) {
return substr($a, 0, strlen($b)) === $b;
}
This function is slightly more complicated as it takes into account a maximum gap length...
function match( string $a, string $b, int $length = 3 ) {
$len = max(strlen($a)-$length, strlen($b));
return substr($a, 0, $len) === $b;
}
So call it something along the lines of
$word1 = 'happyness';
$word2 = 'happys';
if (match($word1,$word2))
{
echo 'same word1';
}
You can use preg_match to match these data with regex as /^word2/ against word1. So regex would check if word1 starts with word2 or not, because of ^ symbol at the start.
It's always better to preg_quote() before matching to escape regex meta characters for accurate results.
<?php
$tests = [
[
'happyness',
'happys'
],
[
'kisses',
'kiss'
],
[
'consonant',
'consonan'
]
];
$filtered = array_filter($tests,function($values){
$values[1] = preg_quote($values[1]);
return preg_match("/^$values[1]/",$values[0]) === 1;
});
print_r($filtered);
Demo: https://3v4l.org/SLf15
You could also do a small function to find the similarity between the given 2 words. It could look like:
function similarity($word1, $word2)
{
$splittedWord1 = str_split($word1);
$splittedWord2 = str_split($word2);
$similarChars = array_intersect_assoc($splittedWord1, $splittedWord2);
return count($similarChars) / max(count($splittedWord1), count($splittedWord2));
}
var_dump(similarity('happyness', 'happys'));
var_dump(similarity('happyness', 'testhappys'));
var_dump(similarity('kisses', 'kiss'));
var_dump(similarity('consonant', 'consonan'));
The result would look like:
float(0.55555555555556)
int(0)
float(0.66666666666667)
float(0.88888888888889)
Based on the resulted percentage you could decide if the given words should be considered the same or not.
I'm not sure regex is the answer here.
You could try similar_text(), which returns the number of similar characters (and optionally sets a percentage value to a variable). Maybe if you consider the last two letters as non-important, you can see if the strlen() - $skippedCharacters is the same as what is matched. For example:
$skippedCharacters = 2;
$word1 = 'kisses';
$word2 = 'kiss';
$match = similar_text($word1, $word2);
if ($match + $skippedCharacters >= strlen($word1))
{
echo 'same word2';
}
You could use the PHP levenshtein function.
The levenshtein() function returns the Levenshtein distance between two strings. The Levenshtein distance is the number of characters you have to replace, insert or delete to transform string1 into string2.
$lev = levenshtein($word1, $word2);
The lower the number the bigger the similarity.

Using PHP preg_replace match result in a math operation?

I want to find a number in a string, add one to it, and replace it. These don't work:
$new_version =
preg_replace("/str\/(\d+)str/", "str/".("$1"+1)."str", $original);
$new_version =
preg_replace("/str\/(\d+)str/", "str/".(intval("$1")+1)."str", $original);
Where 'str' is a very identifiable string, each side of the number (and does not contain numbers).
I realise I can do this in more than one line of code quite easily but it seems like this should be possible.
Using a callback function allows you to cast a match to number and increment, e.g.:
preg_replace_callback(
"/str\/(\d+)str/",
function($matches) { return "str/" . ((int)$matches[1] + 1) . "str"; },
$original
);
Solely using str_replace you can get the number from the string, add one to it, and the replace the old number with the new one :
$str = 'In My Cart : 11 items';
$nb = preg_replace('/\D/', '', $str);
$nb += 1;
$str = str_replace($nb-1, $nb, $str);
echo $str;

Trim comma and whitespacing from number

I am using this function to convert square meters to square foot.
$sinput = rtrim(get_field('fl_area'), ", \t\n");
if(trim($sinput) == "0"){echo ' ' ;} else {$soutput = metersToSquareFeet($sinput); echo $soutput . ' sq. m (' . number_format($sinput ) . ' sq. f)' ;}
function metersToSquareFeet($meters, $echo = true)
{
$m = $meters;
$valInFeet = $m*10.7639;
$valFeet = (int)$valInFeet;
if($echo == true)
{
echo $valFeet;
} else {
return $valFeet;
}
}
Problem I have is with line:
rtrim(get_field('fl_area'), ", \t\n");
The user enters the number in the format 3,246 and i want to convert this to 3246 for my function to work.
Of course I could also modify the function somehow and not use rtrim in the first place
rtrim only removes characters from the end of the string, not the middle. Use preg_replace:
$sinput = preg_replace('/[,\s]+/g', '', get_field('fl_area'));
You have a few options but probably your easiest one is to remove all non-numeric characters.
Not sure what your get_field does but assuming it just gets the field from the Input you could use regex like so.
$sinput = preg_replace( '/[^0-9]/', '', $get_field('fl_area') );
Also see: PHP regular expression - filter number only
You can use str_replace() to remove all occurrences of commas and spaces from the string:
$m = str_replace(array(',',' '), '', $m);
Or even strtr():
$m = strtr($m, array(',' => '', ' ' => ''));
This is likely to be faster than regular expessions. However, if the number of function calls are minimal, the difference wouldn’t be noticeable.
Try this:
str_replace(array(',',' '), '', get_field('fl_area'));

Parse formatted Money String into Number [duplicate]

Is there a way to get the float value of a string like this: 75,25 €, other than parsefloat(str_replace(',', '.', $var))?
I want this to be dependent on the current site language, and sometimes the comma could be replaced by dot.
This is a bit more complex/ slow solution, but works with all locales. #rlenom's solution work only with dots as decimal separator, and some locales, like Spanish, use the comma as decimal separator.
<?php
public function getAmount($money)
{
$cleanString = preg_replace('/([^0-9\.,])/i', '', $money);
$onlyNumbersString = preg_replace('/([^0-9])/i', '', $money);
$separatorsCountToBeErased = strlen($cleanString) - strlen($onlyNumbersString) - 1;
$stringWithCommaOrDot = preg_replace('/([,\.])/', '', $cleanString, $separatorsCountToBeErased);
$removedThousandSeparator = preg_replace('/(\.|,)(?=[0-9]{3,}$)/', '', $stringWithCommaOrDot);
return (float) str_replace(',', '.', $removedThousandSeparator);
}
Tests:
['1,10 USD', 1.10],
['1 000 000.00', 1000000.0],
['$1 000 000.21', 1000000.21],
['£1.10', 1.10],
['$123 456 789', 123456789.0],
['$123,456,789.12', 123456789.12],
['$123 456 789,12', 123456789.12],
['1.10', 1.1],
[',,,,.10', .1],
['1.000', 1000.0],
['1,000', 1000.0]
Caveats:
Fails if the decimal part have more than two digits.
This is an implementation from this library:
https://github.com/mcuadros/currency-detector
use ereg_replace
$string = "$100,000";
$int = ereg_replace("[^0-9]", "", $string);
echo $int;
outputs
1000000
function toInt($str)
{
return (int)preg_replace("/\..+$/i", "", preg_replace("/[^0-9\.]/i", "", $str));
}
Update
<?php
$string = array("$1,000,000.00","$1 000 000.00","1,000 000.00","$123","$123 456 789","0.15¢");
foreach($string as $s) {
echo $s . " = " . toInt($s) . "\n";
}
function toInt($str)
{
return preg_replace("/([^0-9\\.])/i", "", $str);
}
?>
Outputs
$1,000,000.00 = 1000000.00
$1 000 000.00 = 1000000.00
1,000 000.00 = 1000000.00
$123 = 123
$123 456 789 = 123456789
0.15¢ = 0.15
and if you cast it as an integer
<?php
$string = array("$1,000,000.00","$1 000 000.00","1,000 000.00","$123","$123 456 789","0.15¢");
foreach($string as $s) {
echo $s . " = " . _toInt($s) . "\n";
}
function _toInt($str)
{
return (int)preg_replace("/([^0-9\\.])/i", "", $str);
}
?>
outputs
$1,000,000.00 = 1000000
$1 000 000.00 = 1000000
1,000 000.00 = 1000000
$123 = 123
$123 456 789 = 123456789
0.15¢ = 0
So there you have it. single line, one replace. you're good to go.
You can use
NumberFormatter::parseCurrency - Parse a currency number
Example from Manual:
$formatter = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
var_dump($formatter->parseCurrency("75,25 €", $curr));
gives: float(75.25)
Note that the intl extension is not enabled by default. Please refer to the Installation Instructions.
You're gonna need to remove the currency symbol from the string. PHP's intval stops at the 1st non-numeric character it finds.
$int = intval(preg_replace('/[^\d\.]/', '', '$100')); // 100
Though if you have a value like $100.25, you might wanna use floatval instead.
$float = floatval(preg_replace('/[^\d\.]/', '', '$100.25')); // 100.25
PHP has intval (here are the docs), which is (as far as I can tell) exactly the same as JavaScript's parseInt.
However, for what's worth, I don't think either function will help you with what you're trying to do. Because the first character is non-numeric, both freak out (PHP will give you 0, JS will give you NaN). So in either language, you're going to have to do some string/regex parsing.
I'm an newbie, so there's probably an obvious (to others, not me) downside to the approach below, but thought I would share it anyway. I'd be interested to know whether it's faster or slower than using preg_replace, but didn't do any speed testing.
$badChars = array("$", ",", "(", ")");
$dirtyString = "($3,895.23)";
$cleanString = str_ireplace($badChars, "", $dirtyString);
echo "$dirtyString becomes $cleanString<p>";
$dirtyString can be an array, so:
$badChars = array("$", ",", "(", ")");
$dirtyStrings = array("($3,895.23)", "1,067.04", "$5683.22", "$9834.48");
$cleanStrings = str_ireplace($badChars, "", $dirtyStrings);
echo var_dump($cleanStrings);
Casting is your friend:
$int = (int) $string;
Update based on op:
Try something like this:
<?php
function extract_numbers($string)
{
return preg_replace("/[^0-9]/", '', $string);
}
echo extract_numbers('$100');
?>
Demo: http://codepad.org/QyrfS7WE
I had a similar problem where I didn't receive the currency symbol, just the strings (ie: 1,234,567.89 or 1.234.567,89).
This helped me normalize both cases into floats:
$val = str_replace(",", ".", $formatted);
$val = preg_replace("/[\,\.](\d{3})/", "$1", $val);
But Gordon's answer is much cleaner.

Unformat money when parsing in PHP

Is there a way to get the float value of a string like this: 75,25 €, other than parsefloat(str_replace(',', '.', $var))?
I want this to be dependent on the current site language, and sometimes the comma could be replaced by dot.
This is a bit more complex/ slow solution, but works with all locales. #rlenom's solution work only with dots as decimal separator, and some locales, like Spanish, use the comma as decimal separator.
<?php
public function getAmount($money)
{
$cleanString = preg_replace('/([^0-9\.,])/i', '', $money);
$onlyNumbersString = preg_replace('/([^0-9])/i', '', $money);
$separatorsCountToBeErased = strlen($cleanString) - strlen($onlyNumbersString) - 1;
$stringWithCommaOrDot = preg_replace('/([,\.])/', '', $cleanString, $separatorsCountToBeErased);
$removedThousandSeparator = preg_replace('/(\.|,)(?=[0-9]{3,}$)/', '', $stringWithCommaOrDot);
return (float) str_replace(',', '.', $removedThousandSeparator);
}
Tests:
['1,10 USD', 1.10],
['1 000 000.00', 1000000.0],
['$1 000 000.21', 1000000.21],
['£1.10', 1.10],
['$123 456 789', 123456789.0],
['$123,456,789.12', 123456789.12],
['$123 456 789,12', 123456789.12],
['1.10', 1.1],
[',,,,.10', .1],
['1.000', 1000.0],
['1,000', 1000.0]
Caveats:
Fails if the decimal part have more than two digits.
This is an implementation from this library:
https://github.com/mcuadros/currency-detector
use ereg_replace
$string = "$100,000";
$int = ereg_replace("[^0-9]", "", $string);
echo $int;
outputs
1000000
function toInt($str)
{
return (int)preg_replace("/\..+$/i", "", preg_replace("/[^0-9\.]/i", "", $str));
}
Update
<?php
$string = array("$1,000,000.00","$1 000 000.00","1,000 000.00","$123","$123 456 789","0.15¢");
foreach($string as $s) {
echo $s . " = " . toInt($s) . "\n";
}
function toInt($str)
{
return preg_replace("/([^0-9\\.])/i", "", $str);
}
?>
Outputs
$1,000,000.00 = 1000000.00
$1 000 000.00 = 1000000.00
1,000 000.00 = 1000000.00
$123 = 123
$123 456 789 = 123456789
0.15¢ = 0.15
and if you cast it as an integer
<?php
$string = array("$1,000,000.00","$1 000 000.00","1,000 000.00","$123","$123 456 789","0.15¢");
foreach($string as $s) {
echo $s . " = " . _toInt($s) . "\n";
}
function _toInt($str)
{
return (int)preg_replace("/([^0-9\\.])/i", "", $str);
}
?>
outputs
$1,000,000.00 = 1000000
$1 000 000.00 = 1000000
1,000 000.00 = 1000000
$123 = 123
$123 456 789 = 123456789
0.15¢ = 0
So there you have it. single line, one replace. you're good to go.
You can use
NumberFormatter::parseCurrency - Parse a currency number
Example from Manual:
$formatter = new NumberFormatter('de_DE', NumberFormatter::CURRENCY);
var_dump($formatter->parseCurrency("75,25 €", $curr));
gives: float(75.25)
Note that the intl extension is not enabled by default. Please refer to the Installation Instructions.
You're gonna need to remove the currency symbol from the string. PHP's intval stops at the 1st non-numeric character it finds.
$int = intval(preg_replace('/[^\d\.]/', '', '$100')); // 100
Though if you have a value like $100.25, you might wanna use floatval instead.
$float = floatval(preg_replace('/[^\d\.]/', '', '$100.25')); // 100.25
PHP has intval (here are the docs), which is (as far as I can tell) exactly the same as JavaScript's parseInt.
However, for what's worth, I don't think either function will help you with what you're trying to do. Because the first character is non-numeric, both freak out (PHP will give you 0, JS will give you NaN). So in either language, you're going to have to do some string/regex parsing.
I'm an newbie, so there's probably an obvious (to others, not me) downside to the approach below, but thought I would share it anyway. I'd be interested to know whether it's faster or slower than using preg_replace, but didn't do any speed testing.
$badChars = array("$", ",", "(", ")");
$dirtyString = "($3,895.23)";
$cleanString = str_ireplace($badChars, "", $dirtyString);
echo "$dirtyString becomes $cleanString<p>";
$dirtyString can be an array, so:
$badChars = array("$", ",", "(", ")");
$dirtyStrings = array("($3,895.23)", "1,067.04", "$5683.22", "$9834.48");
$cleanStrings = str_ireplace($badChars, "", $dirtyStrings);
echo var_dump($cleanStrings);
Casting is your friend:
$int = (int) $string;
Update based on op:
Try something like this:
<?php
function extract_numbers($string)
{
return preg_replace("/[^0-9]/", '', $string);
}
echo extract_numbers('$100');
?>
Demo: http://codepad.org/QyrfS7WE
I had a similar problem where I didn't receive the currency symbol, just the strings (ie: 1,234,567.89 or 1.234.567,89).
This helped me normalize both cases into floats:
$val = str_replace(",", ".", $formatted);
$val = preg_replace("/[\,\.](\d{3})/", "$1", $val);
But Gordon's answer is much cleaner.

Categories