如何在PowerShell中将字符串转换为双精度浮点数?

9

我有一个PowerShell脚本,用于从CSV导入数据。但是我收到了以下错误:


无法将值“Journal Amount”转换为类型“System.Double”。错误:“输入字符串不符合正确的格式。” 位置 C:\TestPowerShell\TestPowerShell1.ps1:98 字符:1 + $JournalAmount = [double] $_.PSObject.Properties['Journal Amount'].Va ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidArgument: (:) [], RuntimeException + FullyQualifiedErrorId : InvalidCastFromStringToDoubleOrSingle


这是我的代码:

Get-Content "config.txt" | foreach-object -begin {$h=@{}} -process { $k = [regex]::split($_,'='); if(($k[0].CompareTo("") -ne 0) -and ($k[0].StartsWith("[") -ne $True)) { $h.Add($k[0], $k[1]) } }

$FileBrowserInitialDir = $h.FileBrowserInitialDir
$Header = 'Terminal','Company','Journal Account Code','Project','Task','Line of Business','Date','Journal Amount','Report Entry Vendor Description'

$TIDataFilePath = $h.TIDataFilePath
$TIDataFileBaseName = $h.TIDataFileBaseName

$TIScreenID = $h.TIScreenID
$TIControlFile = $h.TIControlFile
$TIErrLog = $h.TIErrLog

$ResultsFilePath = $h.ResultsFilePath
$ResultsFileBaseName = $h.ResultsFileBaseName

$dt = Get-Date -Format "MMddyyyyHHmmss"
$TIDataFile = "$($TIDataFileBaseName)$($dt).txt"
$ResultsFile = "$($ResultsFileBaseName)$($dt).txt"

Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property @{ 
    InitialDirectory = $FileBrowserInitialDir
    Filter = 'CSV (*.csv)|*.csv'
    Title = "Select Expense csv file"
}
$null = $FileBrowser.ShowDialog()

if($FileBrowser.FileName -eq ""){
    exit
}


 $EXPENSECSV = Import-CSV $FileBrowser.FileName -Header $Header
 New-Item -path $TIDataFilePath -name $TIDataFile -type "file"
 $EXPENSECSV |foreach-object{    

$Terminal =  $_.PSObject.Properties['Terminal'].Value
$Terminal = $Terminal.Insert(0,'0')

$CompanyTemp =  $_.PSObject.Properties['Company'].Value
$CompanyTemp = $CompanyTemp.Insert(0,'0')
#$Company= [String]::Concat($_.Terminal,$CompanyTemp) 
$Company= [String]::Concat($Terminal,$CompanyTemp) 
$LineofB =  $_.PSObject.Properties['Line of Business'].Value
#$JournalAmount = [double] $_.PSObject.Properties["Journal Amount"].Value
 $LineofB = $LineofB.Insert(0,'0')

 $Account = $_.PSObject.Properties['Journal Account Code'].Value
$Sub = $LineofB

$TranDateStr =  $_.PSObject.Properties['Date'].Value
$JournalAmount = [double] $_.PSObject.Properties['Journal Amount'].Value
$Description =  $_.PSObject.Properties['Report Entry Vendor Description'].Value

    $row = ""
    $row +=  "`"Level1`","
    $row +=  "`"$($Company)`","
    $row +=  "`"$($Account)`","
    $row +=  "`"$($Sub)`","
    $row +=  "`"$($TranDateStr)`","


    # Convert Concur Amount to Credit/Debit Amount
    # Postive Amount  --> Debit Amount
    # Negative Amount --> Credit Amount
    if($JournalAmount -lt 0){
        $JournalAmount*= -1
        $row += "`"$($JournalAmount)`","   #Credit Amount
        $row += "`"`","             #Debit Amount
    }
    else {
        $row += "`"`","             #Credit Amount
        $row += "`"$($JournalAmount)`","   #Debit Amount
    }

    $row += "`"$($Description)`""

   Add-Content -Path "$($TIDataFilePath)$($TIDataFile)" -Value $row
 }

 #Results
 New-Item -path $ResultsFilePath -name $ResultsFile -type "file"

 $ResultsStr =   "----------------------------------------------------------------------------------`n"
$ResultsStr +=  "                             Concur to Dynamics SL                                   `n"
$ResultsStr +=  "----------------------------------------------------------------------------------`n"
$ResultsStr +=  "Copy and paste the following into the Transaction Import screen.`n"
$ResultsStr += "Line 1: Data File Name`n"
$ResultsStr += "Line 2: Screen ID`n"
$ResultsStr += "Line 3: Control File Name`n"
$ResultsStr += "Line 4: Output Log File`n`n`n"
$ResultsStr += "$($TIDataFilePath)$($TIDataFile)`n"
$ResultsStr += "$($TIScreenID)`n"
$ResultsStr += "$($TIControlFile)`n"
$ResultsStr += "$($TIErrLog)"


 Add-Content -path "$($ResultsFilePath)$($ResultsFile)" -value $ResultsStr

Start-Process "$($ResultsFilePath)$($ResultsFile)"

2
你的 CSV 文件第一行已经有标题了吗?当你在 Import-Csv 中指定 -Header $Header 时,它会将所有行都解释为数据(包括第一行),这就解释了为什么你在“Journal Amount”列中得到了“Journal Amount”值 :) - Mathias R. Jessen
1
你尝试过将无法转换的值写入控制台吗?在出现错误的那一行之前添加一行类似于 Write-Host $_.PSObject.Properties['Journal Amount'].Value 的代码,这可能会帮助你理解为什么该值无法转换为 Double。 - Nick Graham
@Matias R. Jessen...是的,我的CSV文件已经在第一行有标题了。我应该使用什么代替-Header $Header呢? - Boltz
2个回答

14

回答问题:

  • 将字符串转换为[double] - 正如您自己尝试的那样 - 可以成功,但仅当字符串被识别为(浮点数)数字时才能成功。

    • 注意:由于PowerShell的转换是与文化无关的,因此只有 . 被识别为小数点,而, 始终被解释为千位分隔符。

    • 根据文化灵敏度解析,请使用[double]::Parse($string)来基于当前文化规则(反映在$PSCulture中)进行解析;将[cultureinfo]实例作为第二个参数传递以基于给定文化规则进行解析(例如,要基于法国文化规则进行解析,请使用[double]::Parse($string, [cultureinfo] 'fr-FR'))。

  • 如果字符串值未被识别,则可以使用以下方法之一来处理该情况:

    • 使用try / catch来处理错误;例如,将其默认为 0

      • [double] $double = try { $string } catch { 0 }
    • 使用-as,即条件类型转换运算符,它返回指定类型的实例或(如果转换失败)$null

      • $double = $string -as [double]; if ($null -eq $double) { ... }

至于您尝试的内容

正如Mathias R. Jessen所指出的那样,您问题的可能原因是CSV文件本身带有标题行,但您还通过-Header参数提供了标题。

这导致CSV文件的标题行被误读为第一行数据,导致由Import-Csv返回的第一个对象包含列(标题)名称作为属性值 - 这导致[double]转换失败,因为您实际上正在执行以下操作:
[double] 'Journal Amount'

因此:

  • Import-Csv调用中省略-Header参数。

  • 作为优化,使用正常的点表示法简化属性值检索;只需使用引号指定属性名称Journal Amount,因为它包含一个空格:

Import-CSV $FileBrowser.FileName | # !! No -Header argument
  ForEach-Object {
    # Simpler and more efficient than:
    #   $JournalAmount = [double] $_.PSObject.Properties['Journal Amount'].Value
    $JournalAmount = [double] $_.'Journal Amount'
  }
# ...


0

问题已解决:

$JournalAmount = $JournalAmount -as [double]
$JournalAmount = $_.PSObject.Properties['Journal Amount'].Value

1
我认为这并没有解决问题,只是隐藏了错误。由于 $JournalAmount 没有预先定义或给出值,你的第一条语句实际上是无效的操作。第二条语句完全否定了第一条语句的任何影响,并仅将一个 字符串 值存储在 $JournalAmount 中。你可能在考虑对变量进行 _类型约束_,将“转换”放在变量名的 _左侧_:[double] $JournalAmount = $_.PSObject.Properties ['Journal Amount'] .Value;但是,在你的情况下,这并没有帮助到你。 - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接