Solved

Calculations with negative currency numbers

Posted on 2014-02-13
9
241 Views
Last Modified: 2014-02-14
What is the easiest way of doing this

Input:

Product 1           $21.95
Product 1(refund)  -$21.95
Product 2           $12.34

Open in new window

I need to read the values from each line. I don't need to preserve the currency symbol but I do need to do calculations with the value.
Currently using
if (preg_match('/(.*)\s+(-?)\$(\d+.\d\d)/', $input, $r)) {

    //And then
    $amount = $r[3];
    if ($r[2] == '-') $amount *= -1;
...
}

Open in new window

Just wondering if there is a better way of doing this.
0
Comment
Question by:Julian Hansen
  • 5
  • 3
9 Comments
 
LVL 22

Assisted Solution

by:Ivo Stoykov
Ivo Stoykov earned 50 total points
ID: 39858417
Hi
try this
$amount = preg_replace("\D", "", $input);

Open in new window

HTH

Ivo Stoykov
0
 
LVL 51

Author Comment

by:Julian Hansen
ID: 39858471
@Ivo - I am assuming you meant
$amount = preg_replace("/\D/", "", $input);

Open in new window

The code you posted gives an error
preg_replace(): Delimiter must not be alphanumeric or backslash

The \D will leave only digits and I loose the minus sign and the full stop.

The preg_replace does not help me though as I need to extract the currency as part of a wider pattern match - I can't preprocess the string with a preg_replace.

I have many different lines in the file with different patterns I am looking for. Each pattern is unique and will only match one type of line. Therefore the currency with symbol and minus needs to be extracted as part of a single preg_match that also matches other pattrns.

I could apply a preg_replace on the extracted currency value but I can't see how that is better than the solution I am currently using.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39858594
Please see http://www.laprbass.com/RAY_temp_julianh.php

<?php // RAY_temp_julianh.php
error_reporting(E_ALL);

// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28364779.html

// TEST DATA FROM THE POST AT EE
$inp = <<<EOD
Product 1           $21.95
Product 1(refund)  -$21.95
Product 2           $12.34
EOD;

// USE A REGULAR EXPRESSION THAT KEEPS ONLY THE NUMBER-VALUE DATA
$rgx
= '#'         // REGEX DELIMITER
. '['         // START CHARACTER CLASS
. '^'         // NEGATION - MATCH NONE OF THIS CLASS
. '0-9'       // NUMBERS
. '.-'        // DECIMAL POINT AND MINUS SIGN
. ']'         // END CHARACTER CLASS
. '#'         // REGEX DELIMITER
;

// MAKE AN ARRAY SO SE CAN PROCESS EACH LINE ITERATIVELY
$arr = explode(PHP_EOL, $inp);

// PROCESS EACH LINE
foreach ($arr as $str)
{
    // LOCATE THE NUMBER AT THE END
    $sub = explode(' ', $str);
    $end = end($sub);
    $end = preg_replace($rgx, NULL, $end);

    // SHOW THE WORK PRODUCT
    echo PHP_EOL . "<br>$str => $end";
}

Open in new window

0
 
LVL 51

Accepted Solution

by:
Julian Hansen earned 0 total points
ID: 39858669
Thanks Ray - but I think the solution I have already is more optimal.

Exploding the strings on a space won't really help as I would then have to reconstruct the product description string - which might contain N words. In addition I have other patterns I am matching on that contain currency values that do not lend themselves to being split on word boundaries.

Essentially your solution is using the preg_replace option on the extracted currency value which could have been obtained from my original preg_match like so

preg_match('/(.*)\s+(-\$\d+.\d\d)/', $input, $r)

Open in new window


And then applying the preg_replace to $r[2] giving
if (preg_match('/(.*)\s+(-?\$\d+.\d\d)/', $input, $r)) {

    //And then
    $amount = preg_replace("/[^0-9\.-]/", "", $r[2]);
...
}

Open in new window

I am not convinced that the use of preg_replace is better than checking for the minus and modifying the $amount value accordingly.

I was really looking for a "better" way of dealing with this than the one I am currently using.

Another option is as follows
$amount = trim($r[2], '-$') * (($r[2][0] == '-') ? -1 : 1);

Open in new window


All work - just looks messy.
Didn't want to go this route and then find out there was some function or trick that could get the same result more elegantly.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 108

Assisted Solution

by:Ray Paseur
Ray Paseur earned 450 total points
ID: 39858731
As usual the quality of the solution is going to be directly related to the quality of the test data.  If your test data really consists of a string variable with multiple lines delimited by EOL characters and containing freeform data, including an arbitrary number of blanks to pad the lines, with the money-format strings at the end of each line, then you've got a tested and working solution.  You can try to "optimize" this, but I expect that will be like milking a mouse - no matter how much effort you put into the process, you won't get much of a result.

For dollars, the characters you want to keep are the digits, and the optional minus sign and the optional decimal point.  If you're dealing with currencies in some European countries, you need to consider the different meanings of the decimal point and the comma.  The central objective is to reduce the string representations of the currency values to a numeric representation that PHP can use to do arithmetic, that SQL can store in a data base, etc.  I have some experience with PHP and arithmetic and I know of no function that can reverse the effects of number_format() or money_format() because these functions turn float values into string representations.  The are intended to prepare internal data for document output.  In the instant case, it looks like you're working with document output, but using it as input to an additional process.

PHP has rules governing the way string representations of numbers can be converted to numbers.  If all you had to deal with was the dollar sign, you might just use str_replace() to remove the dollar sign.  Then you could let PHP duck-typing work on your behalf and you could do arithmetic with the resulting string representations of number values.
http://www.php.net/manual/en/language.types.string.php#language.types.string.conversion

The way PHP handles loose data types has not always been consistent.
http://www.php.net/manual/en/migration51.integer-parameters.php
http://www.php.net/manual/en/language.types.type-juggling.php

If you have time to spend on the project, you might experiment with sscanf(), but I doubt if I would bother with that.  I've used the regular expression I posted above in many applications and it's always done the job for me.  The rest of the script is just about isolating the dollar values which are intermixed into the test data string, and there are many ways of doing that.
0
 
LVL 51

Author Comment

by:Julian Hansen
ID: 39858751
Thanks Ray, the question was about the best way of turning -$21.95 into a number - the parsing of the string is not in question.

My main objective was to discover if there was a more elegant approach than the one I was using - I think the follwoing comment sums it up
I know of no function that can reverse the effects of number_format() or money_format()

I will use either my original solution or the solution in my last post.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 39859462
Well, that changes the question a bit.  Use whatever you feel comfortable with -- I feel comfortable with this regular expression.

<?php // RAY_temp_julianh.php
error_reporting(E_ALL);

// SEE http://www.experts-exchange.com/Web_Development/Web_Languages-Standards/PHP/Q_28364779.html#a39858751

// TEST DATA FROM THE CLARIFIED EXPLANATION AT EE
$inp = '-$21.95';

// USE A REGULAR EXPRESSION THAT KEEPS ONLY THE NUMBER-VALUE DATA
$rgx
= '#'         // REGEX DELIMITER
. '['         // START CHARACTER CLASS
. '^'         // NEGATION - MATCH NONE OF THIS CLASS
. '0-9'       // NUMBERS
. '.-'        // DECIMAL POINT AND MINUS SIGN
. ']'         // END CHARACTER CLASS
. '#'         // REGEX DELIMITER
;

// IS IT NUMERIC?
echo "<br>$inp";
if (is_numeric($inp))
{
    echo ' IS NUMERIC';
}
else
{
    echo ' IS NOT NUMERIC';
}

// REDACT THE STRING VARIABLE
$new = preg_replace($rgx, NULL, $inp);

// IS IT NUMERIC?
echo "<br>$new";
if (is_numeric($new))
{
    echo ' IS NUMERIC';
}
else
{
    echo ' IS NOT NUMERIC';
}

Open in new window

0
 
LVL 51

Author Comment

by:Julian Hansen
ID: 39860135
Thanks Ray, apologies if the question was phrased in a confusing way.

I do not need code for parsing the line - I feel my approach wth preg_match is optimal for for the requirements of the project.

I was only trying to find out if there was a standard way with converting currency strings back into floating point values so they can be used in calculations.

Given there does not seem to be a standard way of doing this I will leave my solution as it stands.
0
 
LVL 51

Author Closing Comment

by:Julian Hansen
ID: 39860150
I am choosing my own solution as none of the answers posted resulted in my changing my implementation.

I have awarded a B grade as the solutions presented were not used but they could provide some info to others reading this post.

@Ivo - points for the \D - did not ultimately do what I needed but it did lead to my solving another related problem.

@ray - comprehensive as always - and useful to whoever might read this link.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Deprecated and Headed for the Dustbin By now, you have probably heard that some PHP features, while convenient, can also cause PHP security problems.  This article discusses one of those, called register_globals.  It is a thing you do not want.  …
These days socially coordinated efforts have turned into a critical requirement for enterprises.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now