Format floats and unformat currencies

  • Format a float number to a locale's currency or decimal format.
  • Remove the formatting of a number to convert it to a float that you can save in a database.

Code

https://www.php.net/manual/en/class.numberformatter.php

  • format_*() functions return strings
  • parse_*() functions return floats
  • NumberFormatter::TYPE_CURRENCY does not work
function format_currency($locale, $value, $currency = NULL) {
    $fmt = numfmt_create($locale, NumberFormatter::CURRENCY);
    $currency = @$currency ?: numfmt_get_symbol($fmt, NumberFormatter::INTL_CURRENCY_SYMBOL);
    return numfmt_format_currency($fmt, $value, $currency);
}
function parse_currency($locale, $string) {
    $fmt = numfmt_create($locale, NumberFormatter::CURRENCY);
    return numfmt_parse_currency($fmt, $string, $currency);
}
function format_accounting($locale, $value, $currency = NULL) {
    $fmt = numfmt_create($locale, NumberFormatter::CURRENCY_ACCOUNTING);
    $currency = @$currency ?: numfmt_get_symbol($fmt, NumberFormatter::INTL_CURRENCY_SYMBOL);
    return numfmt_format_currency($fmt, $value, $currency);
}
function parse_accounting($locale, $string) {
    $fmt = numfmt_create($locale, NumberFormatter::CURRENCY_ACCOUNTING);
    return numfmt_parse_currency($fmt, $string, $currency);
}
function format_decimal($locale, $value, $type = NULL) {
    $fmt = numfmt_create($locale, NumberFormatter::DECIMAL);
    $type = @$type ?: NumberFormatter::TYPE_DEFAULT;
    return numfmt_format($fmt, $value, $type);
}
function parse_decimal($locale, $string, $type = NULL) {
    $fmt = numfmt_create($locale, NumberFormatter::DECIMAL);
    $type = @$type ?: NumberFormatter::TYPE_DOUBLE;
    return numfmt_parse($fmt, $string, $type);
}
function ascii($string) {
    return str_replace(["\xe2\x80\xaf", "\xc2\xa0"], ' ', $string);
}

Usage

function output() {
    $value = -1000.01;
    $locales = ['en_US', 'fr_FR', 'de_DE', 'nl_NL', 'ru_RU'];
    $html = [];
    foreach ($locales as $locale) {
        $string = format_currency($locale, $value);
        $ascii = ascii($string);
        $value = parse_currency($locale, $string);
        $html []= $locale . ' Currency   '. ' => float: ' . $value . ' | ASCII: ' . $ascii . ' | UTF-8: ' . $string;
        $string = format_accounting($locale, $value);
        $ascii = ascii($string);
        $value = parse_accounting($locale, $string);
        $html []= $locale . ' Accounting '. ' => float: ' . $value . ' | ASCII: ' . $ascii . ' | UTF-8: ' . $string;
        $string = format_decimal($locale, $value);
        $ascii = ascii($string);
        $value = parse_decimal($locale, $string);
        $html []= $locale . ' Decimal    '. ' => float: ' . $value . ' | ASCII: ' . $ascii . ' | UTF-8: ' . $string;
    }
    echo join(PHP_EOL, $html);
}
output();

Output

On the screenshot, you see the narrow no-break space <0x202f> and the no-break space <0xa0>; not visible on HTML.

output

en_US Currency    => float: -1000.01 | ASCII: -$1,000.01 | UTF-8: -$1,000.01
en_US Accounting  => float: -1000.01 | ASCII: ($1,000.01) | UTF-8: ($1,000.01)
en_US Decimal     => float: -1000.01 | ASCII: -1,000.01 | UTF-8: -1,000.01
fr_FR Currency    => float: -1000.01 | ASCII: -1 000,01 € | UTF-8: -1 000,01 €
fr_FR Accounting  => float: -1000.01 | ASCII: (1 000,01 €) | UTF-8: (1 000,01 €)
fr_FR Decimal     => float: -1000.01 | ASCII: -1 000,01 | UTF-8: -1 000,01
de_DE Currency    => float: -1000.01 | ASCII: -1.000,01 € | UTF-8: -1.000,01 €
de_DE Accounting  => float: -1000.01 | ASCII: -1.000,01 € | UTF-8: -1.000,01 €
de_DE Decimal     => float: -1000.01 | ASCII: -1.000,01 | UTF-8: -1.000,01
nl_NL Currency    => float: -1000.01 | ASCII: € -1.000,01 | UTF-8: € -1.000,01
nl_NL Accounting  => float: -1000.01 | ASCII: (€ 1.000,01) | UTF-8: (€ 1.000,01)
nl_NL Decimal     => float: -1000.01 | ASCII: -1.000,01 | UTF-8: -1.000,01
ru_RU Currency    => float: -1000.01 | ASCII: -1 000,01 ₽ | UTF-8: -1 000,01 ₽
ru_RU Accounting  => float: -1000.01 | ASCII: -1 000,01 ₽ | UTF-8: -1 000,01 ₽
ru_RU Decimal     => float: -1000.01 | ASCII: -1 000,01 | UTF-8: -1 000,01