3

I'm fetching data based on two values​​. The price of a product and the discount on the product. And I want to calculate the difference. The problem is that the values ​​come from the database such as: 22,50 €. I grab this value, I'm removing the "€" and replace "," by "." . But the problem is that when doing subtraction of values​​, the account is not taken.

database comes the variable $discount and $price

 $price2 = trim($price,'€'); 
 $price2 = str_replace(",",".",$price2);
 $price2 = floatval($price2);

 $discount2 = str_replace(array('€'), '',$discount); 
 $discount2 = str_replace(",",".",$discount2);
 $discount2 = floatval($ver_preco2);


 $result = ($price2 - $discount2);

The variable $discount is not being converted to float and not know why. What is the problem in the variable?

pc_oc
  • 535
  • 3
  • 8
  • 26

1 Answers1

2

As this question has been viewed many times, I've put together a function that may be useful to others who find this question. The following is a script containing some test values, the function currencyToDecimal(), and then a bit of code to run and display the tests. You only need the function itself.

If you have other test cases that do not pass, please let me know so we can adapt this.

<?php

    $testValues = [
        '22,50 €',
        '22 €',
        '22€',
        '$22.50',
        '$22',
        '$0.50¢',
        '$22 000 000.50',
        '22 000 000,50 €',
        '22.000.000,50 €',
    ];

    /**
     * Convert Currency String to Decimal
     * 
     * Attempts to support international currency formats by first converting them
     * to a standardized format PHP can process consistently. 
     * 
     * First, per the SI/ISO 31-0 standard, there are several delimiting options
     * for the integer portion (before the radix) that allow for easier reading. We need
     * to convert this portion to an integer without readability delimiters.
     * 
     * Second, we need to convert the radix (decimal separator) to a "point" or 
     * "period" symbol.
     * 
     * Finally, we strip unwanted characters and convert to float.
     * 
     * @see https://en.wikipedia.org/wiki/Decimal_separator
     * @see https://en.wikipedia.org/wiki/ISO_31-0
     * @see https://docs.oracle.com/cd/E19455-01/806-0169/overview-9/index.html
     */
    function currencyToDecimal($value) {

        // Ensure string does not have leading/trailing spaces
        $value = trim($value);

        /**
         * Standardize readability delimiters
         *****************************************************/

            // Space used as thousands separator between digits
            $value = preg_replace('/(\d)(\s)(\d)/', '$1$3', $value); 

            // Decimal used as delimiter when comma used as radix
            if (stristr($value, '.') && stristr($value, ',')) {
                // Ensure last period is BEFORE first comma
                if (strrpos($value, '.') < strpos($value, ',')) {
                    $value = str_replace('.', '', $value);
                }
            }

            // Comma used as delimiter when decimal used as radix
            if (stristr($value, ',') && stristr($value, '.')) {
                // Ensure last period is BEFORE first comma
                if (strrpos($value, ',') < strpos($value, '.')) {
                    $value = str_replace(',', '', $value);
                }
            }

        /**
         * Standardize radix (decimal separator)
         *****************************************************/

            // Possible radix options
            $radixOptions = [',', ' '];

            // Convert comma radix to "point" or "period"
            $value = str_replace(',', '.', $value);

        /**
         * Strip non-numeric and non-radix characters
         *****************************************************/

            // Remove other symbols like currency characters
            $value = preg_replace('/[^\d\.]/', '', $value);

        /**
         * Convert to float value
         *****************************************************/

            // String to float first before formatting
            $value = floatval($value);

        /**
         * Give final value 
         *****************************************************/

            return $value;

    }

    // Run tests through function
    echo("ORIGINAL => DECIMAL => DATA TYPE\n");
    echo("*********************************************\n");
    foreach ($testValues as $value) {

        // Run function on test value
        $result = currencyToDecimal($value);

        // Determine data type. NOTE: Per docs, "double" will be 
        // returned for a "float" value.
        $type = gettype($result);
        if ($type === "double") {
            $type = "float";
        }

        // Output [Original] => [Decimal] => [Data Type]
        echo("$value => $result => $type\n");
    }

The output is as follows:

Test Output

ORIGINAL => DECIMAL => DATA TYPE
*********************************************
22,50 € => 22.5 => float
22 € => 22 => float
22€ => 22 => float
$22.50 => 22.5 => float
$22 => 22 => float
$0.50¢ => 0.5 => float
$22 000 000.50 => 22000000.5 => float
22 000 000,50 € => 22000000.5 => float
22.000.000,50 € => 22000000.5 => float

References:
https://en.wikipedia.org/wiki/Decimal_separator
https://en.wikipedia.org/wiki/ISO_31-0
https://docs.oracle.com/cd/E19455-01/806-0169/overview-9/index.html

Jeremy Harris
  • 24,318
  • 13
  • 79
  • 133