【问题标题】:Using Sort-Object to sort a Currency/Money使用 Sort-Object 对货币/货币进行排序
【发布时间】:2022-07-12 00:00:35
【问题描述】:

我有一个来自我公司的库存数据库,我想根据定价对一些条目进行排序。我原本以为我必须手动完成所有操作,但我认为 Sort-Object 应该可以工作……直到我想起了 Sort-Object 及其臭名昭著的字符串排序。很简单,我会通过将其转换为整数进行排序,当然货币值的开头有 $ 之类的符号。

我使用的导致字符串排序的原始代码如下。经典200高于1000等:

$Result | Sort-Object -Property Price | Format-Table -Property Price

我试过的int代码是:

$Result | Sort-Object -Property { [int]$_.Price } | Format-Table -Property Price

这会导致类似“无法将值“$414.50”转换为类型“System.Int32”的输出。| 错误:“输入字符串的格式不正确。”有道理,无法将 $ 转换为 int。

那么有什么办法可以不用我手动排序吗?

谢谢

【问题讨论】:

  • 替换$并转换为十进制类型:... |Sort-Object -Property { $_.Price.Replace('$','') -as [decimal]}

标签: powershell sorting currency sort-object


【解决方案1】:

首先,您可能需要[decimal] 而不是[int],因为[int] "414.50"414,而不是414.50,因此您将失去精度。

除此之外,我正在为 C# 调整这个答案:https://stackoverflow.com/a/56603818/3156906

$fi = new-object System.Globalization.NumberFormatInfo;
$fi.CurrencySymbol = "`$";

@("`$10.00", "`$2.00") | Sort-Object -Property @{
    "Expression" = { [decimal]::Parse($_, "Currency", $fi) }
};
# $2.00
# $10.00

这样做的好处是无效的数据库值,例如 - 例如$1.$10 - 这可能会引发异常,£1.00 等不同的货币也会引发异常,因此您可以免费获得一些额外的数据验证。

请注意,结果仍为字符串,但按货币金额(小数)排序。如果您想要实际的数值,则需要分别转换这些值...

【讨论】:

  • 好消息,但请注意,您可以简单地将[cultureinfo] 'en-US' 传递给:;Parse() 调用,而无需构造NumberFormatInfo 实例。此外,仅接受数字(不带货币符号);例如[decimal]::Parse('9.99', 'C', [cultureinfo] 'en-US'),后置符号也是如此,例如`[decimal]::Parse('9.99$', 'C', [cultureinfo] 'en-US')
【解决方案2】:

添加到mclayton's helpful answer

[decimal]::Parse() 调用中使用使用您的货币格式的预定义[cultureinfo] 实例 更简单,例如[decimal]::Parse() 调用中的en-US(美国英语),结合@987654331 @,currency format specifier

@(
  [pscustomobject] @{ Price='$414.50' },
  [pscustomobject] @{ Price='99.02$' }
  [pscustomobject] @{ Price='999.03' }
  [pscustomobject] @{ Price='$5.04' }
) | 
  Sort-Object { [decimal]::Parse($_.Price, 'C', [cultureinfo] 'en-US') }

输出(按正确的数字排序):

Price
-----
$5.04
99.02$
$414.50
999.03

注意:

  • 如示例输入值所示,在接受哪些输入格式方面存在一定的灵活性,例如 尾随 $不带 @987654335 的值@。

  • 如果当前文化可以假定为en-US(或使用相同货币符号和格式的不同文化,尤其是相同的小数分隔符.),您可以省略上述 [decimal]::Parse() 调用中的 [cultureinfo] 'en-US' 参数 - 尽管为了稳健性我建议保留它。

    • 顺便说一句:PowerShell 的 casts(不支持货币值)始终使用带有字符串操作数的 invariant culture,而与 当前 文化无关。因此,即使在使用 , 作为小数点分隔符的文化有效时,也会识别像 [decimal] '3.14' 这样的内容。

    • 虽然不变文化(其目的是提供不依赖于文化并随着时间保持稳定的表示)基于美式英语文化,但它可以不 在这里使用,因为它的货币符号是¤;例如,(9.99).ToString('C', [cultureinfo]::InvariantCulture) 产生 ¤9.99

  • 无法解析为货币的输入值会导致(有效地)非终止错误,[1] 并且此类值在货币值之前排序。

    • 如果您只想忽略不符合要求的值,请使用try { [decimal]::Parse(...) } catch { }
    • 如果您想在遇到非确认值时中止处理,请将 -ErrorAction Stop 传递给 Sort-Object 调用。

[1] 失败的 .NET 方法调用会导致 statement-terminating 错误,但由于错误发生在 脚本块 中(在上下文中calculated property),只有脚本块内的语句被终止,而不是封闭的 Sort-Object 调用

【讨论】:

    猜你喜欢
    • 2013-09-06
    • 2016-01-07
    • 2020-10-20
    • 2015-09-08
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多