使用不带货币符号的 Intl.NumberFormat 进行货币格式化

Posted

技术标签:

【中文标题】使用不带货币符号的 Intl.NumberFormat 进行货币格式化【英文标题】:Currency formatting using Intl.NumberFormat without currency symbol 【发布时间】:2021-07-27 16:58:10 【问题描述】:

我正在尝试使用 Intl 作为默认货币格式化程序,它几乎是完美的。

使用Intl.NumberFormat() constructor 中的示例:

const number = 123456.789;

console.log(new Intl.NumberFormat('de-DE',  style: 'currency',
currency: 'EUR' ).format(number)); // expected output: "123.456,79 €"
 
// the Japanese yen doesn't use a minor unit 
console.log(new Intl.NumberFormat('ja-JP',  style: 'currency', currency: 'JPY'
).format(number)); // expected output: "¥123,457"

这几乎是完美的,但我实际上想从输出中删除符号。所以我希望看到:

// expected output: "123.456,79"
// expected output: "123,457"

奇怪的是,我花了一个多小时寻找解决方案,却只发现了某种替换/修剪用法。

为什么没有一个选项来格式化具有所有 Intl 功能的数字,而只删除货币符号?!?

希望我错过了,tbh。

【问题讨论】:

【参考方案1】:

实现您想要的一种简单方法是使用String#replace() 从字符串中删除货币。为简化此操作,您可以将 currencyDisplay 设置为 "code",这将使用 ISO 货币代码 - 与传递给 currency 的相同:

const number = 123456.789;

console.log(new Intl.NumberFormat('de-DE',  
    style: 'currency',
    currency: 'EUR', 
    currencyDisplay: "code" 
  )
  .format(number)
  .replace("EUR", "")
  .trim()
); // 123.456,79
 
// the Japanese yen doesn't use a minor unit 
console.log(new Intl.NumberFormat('ja-JP',  
    style: 'currency', 
   currency: 'JPY', 
    currencyDisplay: "code" 
  )
  .format(number)
  .replace("JPY", "")
  .trim()
); // 123,457

这可以提取成一个函数:

const number = 123456.789;

console.log(format('de-DE', 'EUR', number)); // 123.456,79
console.log(format('ja-JP', 'JPY', number)); // 123,457

function format (locale, currency, number) 
  return new Intl.NumberFormat(locale,  
    style: 'currency', 
    currency, 
    currencyDisplay: "code" 
  )
  .format(number)
  .replace(currency, "")
  .trim();

允许您进行更多控制的另一种方法是使用Intl.NumberFormat#formatToParts(),它会格式化数字,但会为您提供可以以编程方式使用和操作的令牌。例如,使用locale = "de-DE"currency = "EUR" 的方法会得到以下输出:

[
  
    "type": "integer",
    "value": "123"
  ,
  
    "type": "group",
    "value": "."
  ,
  
    "type": "integer",
    "value": "456"
  ,
  
    "type": "decimal",
    "value": ","
  ,
  
    "type": "fraction",
    "value": "79"
  ,
  
    "type": "literal",
    "value": " "
  ,
  
    "type": "currency",
    "value": "EUR"
  
]

这意味着您可以轻松过滤掉"type": "currency",然后将其余部分组合成一个字符串。例如:

const number = 123456.789;

console.log(format('de-DE', 'EUR', number)); // 123.456,79
console.log(format('ja-JP', 'JPY', number)); // 123,457

function format (locale, currency, number) 
  return new Intl.NumberFormat(locale,  
    style: 'currency',
    currency, 
    currencyDisplay: "code" 
  )
  .formatToParts(number)
  .filter(x => x.type !== "currency")
  .map(x => x.value)
  .join("")
  .trim()

【讨论】:

感谢您的调查。我理解你说移除货币可能是一件奇怪的事情,但我不这么认为。我的用例是在表格列中显示成本。我不想在每个单元格中重复该符号。我只想将它添加到标题中。对我来说,格式和符号是两个不同的东西。在我看来,任何想以这种方式实现它的人都犯了一个错误。至少他们应该添加currencyDisplay: "none" 是的,我同意currencyDisplay: "none" 最有意义。但是,(在这里推测)设计者可能认为不需要它,因为可以移除货币。没有把握。也就是说,如果这是有意没有添加的。这可能是一个无意的遗漏。 话虽如此,我才发现昨天我显然完全失明了。我确实搜索了.formatToParts(),我知道它存在日期但不知何故没有看到NumberFormat。我已将其添加为选项。 哈! .formatToParts() 正是我在当前实现中所拥有的!非常好!

以上是关于使用不带货币符号的 Intl.NumberFormat 进行货币格式化的主要内容,如果未能解决你的问题,请参考以下文章

为啥AngularJS货币过滤器格式负数用括号

REGEX 提取金额不带货币

不带“$”的 Cocoa NSNumberFormatterCurrencyStyle 返回零

react-intl 货币显示不带小数

使用swift从货币代码中获取货币符号

用货币符号在前面格式化货币