How do I get NumberFormatter to print negative cur

2019-04-26 00:27发布

问题:

I'm using the PHP NumberFormatter class to print currency values.

Eg:

  $cFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
  $cFormatter->formatCurrency(123, 'USD');
  $cFormatter->formatCurrency(123, 'BRL');
  $cFormatter->formatCurrency(123, 'GBP');

That works fine, and returns "$123.00", "R$123.00", "£123.00" respectively as expected.

But negative numbers are printed "accountancy style", surrounded by brackets, instead of a leading minus "-".

eg:

$cFormatter->formatCurrency(-456, 'USD');

Returns "($456.00)", whereas I want "-$456.00". Surely there's a simple way of doing this?

I can remove the brackets by override the prefix and postfix as follows:

$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_PREFIX, "-");
$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_SUFFIX, "");

But then I get no currency symbol eg "-456.00".

Is there some escape code for the currency symbol that I need to use when setting the NEGATIVE_PREFIX attribute?

Edit: I'm happy to set a different locale if that gives me the result I'm looking for.

Edit 2: Looking at the Intl library docs (which is the library used to implement NumberFormatter), the following looked promising:

¤ (\u00A4) : Prefix or suffix : No Currency sign, replaced by currency symbol. If doubled, replaced by international currency symbol. If tripled, replaced by currency plural names, for example, "US dollar" or "US dollars" for America. If present in a pattern, the monetary decimal separator is used instead of the decimal separator.

But this:

$cFormatter->setTextAttribute(NumberFormatter::NEGATIVE_PREFIX, "-¤");

Just prints "-¤123", so no joy.

Edit 3: I think I found the answer, see below.

回答1:

I've found a slightly less hacky way to bend the en_US locale behaviour to what I'm looking for - the getPattern() / setPattern() functions.

$cFormatter = new NumberFormatter('en_US', NumberFormatter::CURRENCY);
$sPattern = $cFormatter->getPattern(); // returns "¤#,##0.00;(¤#,##0.00)";

$sMyPattern = "¤#,##0.00;-¤#,##0.00";
$cFormatter->setPattern($sMyPattern);
$cFormatter->formatCurrency(-456, 'USD');  // returns -$456.00


回答2:

By doing so, you are kinda ruining the point of the localization. Since the ¤ represent the dollar sign and your are telling that your pattern always puts the sign in the beginning of the number, which is not the case for every currency. If you want to remove the parenthesis, I would go something more like,

$locale = 'en_US';    
$nf = new \NumberFormatter($locale, \NumberFormatter::CURRENCY); 
$nf->setAttribute(\NumberFormatter::MAX_FRACTION_DIGITS, $decimals);

$pattern = str_replace(array('(',')'),'',$nf->getPattern());
$nf->setPattern($pattern);

echo $nf->format($number);


回答3:

Simply you can do

$cFormatter->setTextAttribute(NumberFormatter::PAD_BEFORE_PREFIX, '-$')."\n";