基于任意区域性设置将字符串转换为数字



我需要对基于区域性格式化的文本文件中的数字进行一些数学运算,所以我可以得到1234.56,或者我可以得到1.234,56,甚至1234,56。我原本想通过了解当前的文化

$culture = (Get-Culture).Name

然后将所有数字转换为en-US格式,进行数学运算,然后转换回原始格式。然而,像这样简单的事情是行不通的。

$useCulture = New-Object System.Globalization.CultureInfo("en-US")
$value1 = "1,234.56"
$value2 = "1234,56"
[double]$value1 = $value1.ToString("f", $useCulture)
[double]$value2 = $value2.ToString("f", $useCulture)
$value1
$value2

我希望这两个值都能返回1234.56,但第二个值返回为123456,所以很明显我不理解ToString是如何工作的。我的猜测是,它假设它所拥有的是美国格式,因为这就是我的机器的配置,然后它试图转换为相同的东西,而在$value2上,它只是假设数千分隔符放错了地方?在任何情况下,我将如何从任意格式转换为指定格式,以便确保总和正确,然后再转换回原始的任意格式?或者,我是不是完全错过了什么,有更好的方法来解决这个问题?此外,如果可能的话,我希望能够使用PS 2.0做到这一点,因为我不能依赖于目标机器升级到新版本。

因此,如果总体结果是你想要的东西只有数字,最多只有一个小数点,我会尝试以下方法:

  • 将任何非小数点替换为点
  • 去掉最后一个点以外的所有点,我们将其视为小数点

以下是一个适用于一些测试用例的示例函数,但我在测试中肯定没有详尽无遗:

function ConvertTo-Number {
  param(
    [Parameter(
      Mandatory=$true)]
      [System.String]
      $String
  )
  if($String -notmatch 'D'){
    return [int]$String
  } else {
    $ConvertedValue = ($String -replace 'D','.') -match '^(?<int>.*?)(?<dec>[d]*)$'
    $ConvertedValue = $matches["int"] -replace 'D',''
    if($matches["dec"]){
      $ConvertedValue+=".$($matches["dec"])"
    }
    return [double]$ConvertedValue
  }
}

如果可能的话,您可能需要先清理输入字符串,例如,在进行其他操作之前删除空格。

您可以执行以下操作:

# Your input value
$value = '1 234,56'
# Determine culture of input format
if ($value -match '.dd$') {
    $culture = [cultureinfo]::GetCultureInfo('en-us')
} elseif ($value -match '.ddd') {
    $culture = [cultureinfo]::GetCultureInfo('de-de')
} elseif ($value -match ' ddd|,dd$') {
    $culture = [cultureinfo]::GetCultureInfo('fr-fr')
}
# Parse input value into a double and perform math, e.g. value * 27.2
$newvalue = [double]::Parse($value,$culture) * 27.2
# Convert computed value back to original culture
$newvalue.ToString('n2',$culture)

最新更新