【问题标题】:ConvertTo-Csv Output without quotesConvertTo-Csv 输出不带引号
【发布时间】:2014-07-27 06:34:13
【问题描述】:

我正在使用ConvertTo-Csv 来获取逗号分隔的输出

get-process | convertto-csv -NoTypeInformation -Delimiter ","

输出如下:

"__NounName","Name","Handles","VM","WS",".....

但是我想得到不带引号的输出,比如

__NounName,Name,Handles,VM,WS....

【问题讨论】:

    标签: powershell csv


    【解决方案1】:

    这是一种去除引号的方法

    get-process | convertto-csv -NoTypeInformation -Delimiter "," | % {$_ -replace '"',''} 
    

    但是如果其中一个项目包含",它将被删除!

    【讨论】:

    • 这可能不适用于get-process 的输出,但此解决方案也会对其中包含特殊字符的字段进行转义。 (例如“aaa”、“bbb”、“cc,cc”、“ddd”)。
    • @SteveGuidi 你是对的,答案中写了。
    【解决方案2】:

    嗯,我的 Mac 上有 Powershell 7 preview 1,Export-Csv 有一个 -UseQuotes 选项,您可以将其设置为 Never。 :)

    【讨论】:

    • 这对旧版本的 PowerShell 没有帮助。看来Kory Gill's answer 在这种情况下效果最好。
    【解决方案3】:

    我今天在一张桌子上工作,并在我在记事本中预览 CSV 文件时考虑了这个问题,并决定看看其他人想出了什么。似乎许多人的解决方案过于复杂。
    这是从 PowerShell 中的 Export-Csv cmdlet 生成的 CSV 文件中删除引号的真正简单方法。

    使用以下数据创建一个 TEST.csv 文件。

    “ID”、“姓名”、“州”
    “5”,“斯蒂芬妮”,“亚利桑那”
    "4","梅兰妮","俄勒冈"
    “2”,“凯蒂”,“德克萨斯”
    “8”,“史蒂夫”,“爱达荷”
    "9","多莉","田纳西"

    另存为:TEST.csv

    将文件内容存储在 $Test 变量中
    $Test = Get-Content .\TEST.csv

    加载 $Test 变量以查看 get-content cmdlet 的结果
    $Test

    再次加载 $Test 变量并将所有 ( "," ) 替换为逗号,然后通过删除每个引号来修剪开头和结尾

    $Test.Replace('","',",").TrimStart('"').TrimEnd('"')
    

    保存/替换 TEST.csv 文件

    $Test.Replace('","',",").TrimStart('"').TrimEnd('"') | Out-File .\TEST.csv -Force -Confirm:$false
    

    使用 Import-Csv 和 Get-Content 测试新文件输出:

    Import-Csv .\TEST.csv
    Get-Content .\TEST.csv
    

    总而言之,两行代码就可以完成这项工作

    $Test = Get-Content .\TEST.csv
    $Test.Replace('","',",").TrimStart('"').TrimEnd('"') | Out-File .\TEST.csv -Force -Confirm:$false
    

    【讨论】:

      【解决方案4】:

      我遇到了这个问题,找到了这个问题,但对答案不满意,因为如果您使用的数据包含分隔符,它们似乎都会受到影响,应该保持引用。去掉不需要的双引号是件好事。

      下面的解决方案似乎可以解决一般情况下的这个问题,以及所有可能导致问题的变体。

      我在其他地方找到了这个答案,Removing quotes from CSV created by PowerShell,并用它为 SO 社区编写了一个示例答案。

      署名: 正则表达式的功劳,100% 归于 Russ Loski。

      函数中的代码,Remove-DoubleQuotesFromCsv

      function Remove-DoubleQuotesFromCsv
      {
          param (
              [Parameter(Mandatory=$true)]
              [string]
              $InputFile,
      
              [string]
              $OutputFile
          )
      
          if (-not $OutputFile)
          {
              $OutputFile = $InputFile
          }
      
          $inputCsv = Import-Csv $InputFile
      
          $quotedData = $inputCsv | ConvertTo-Csv -NoTypeInformation
      
          $outputCsv = $quotedData | % {$_ -replace  `
              '\G(?<start>^|,)(("(?<output>[^,"]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$)))' `
              ,'${start}${output}'}
      
          $outputCsv | Out-File $OutputFile -Encoding utf8 -Force
      }
      

      测试代码

      $csvData = @"
      id,string,notes,number
      1,hello world.,classic,123
      2,"a comma, is in here","test data 1",345
      3,",a comma, is in here","test data 2",346
      4,"a comma, is in here,","test data 3",347
      5,"a comma, is in here,","test data 4`r`nwith a newline",347
      6,hello world2.,classic,123
      "@
      
      $data = $csvData | ConvertFrom-Csv
      "`r`n---- data ---"
      $data
      
      $quotedData = $data | ConvertTo-Csv -NoTypeInformation
      "`r`n---- quotedData ---"
      $quotedData
      
      # this regular expression comes from:
      # http://www.sqlmovers.com/removing-quotes-from-csv-created-by-powershell/
      $fixedData = $quotedData | % {$_ -replace  `
        '\G(?<start>^|,)(("(?<output>[^,"\n]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$)))' `
        ,'${start}${output}'}
      "`r`n---- fixedData ---"
      $fixedData
      
      $fixedData | Out-File e:\test.csv -Encoding ascii -Force
      "`r`n---- e:\test.csv ---"
      Get-Content e:\test.csv
      

      测试输出

      ---- data ---
      
      id string               notes                       number
      -- ------               -----                       ------
      1  hello world.         classic                     123   
      2  a comma, is in here  test data 1                 345   
      3  ,a comma, is in here test data 2                 346   
      4  a comma, is in here, test data 3                 347   
      5  a comma, is in here, test data 4...              347   
      6  hello world2.        classic                     123   
      
      ---- quotedData ---
      "id","string","notes","number"
      "1","hello world.","classic","123"
      "2","a comma, is in here","test data 1","345"
      "3",",a comma, is in here","test data 2","346"
      "4","a comma, is in here,","test data 3","347"
      "5","a comma, is in here,","test data 4
      with a newline","347"
      "6","hello world2.","classic","123"
      
      ---- fixedData ---
      id,string,notes,number
      1,hello world.,classic,123
      2,"a comma, is in here",test data 1,345
      3,",a comma, is in here",test data 2,346
      4,"a comma, is in here,",test data 3,347
      5,"a comma, is in here,","test data 4
      with a newline","347"
      6,hello world2.,classic,123
      
      ---- e:\test.csv ---
      id,string,notes,number
      1,hello world.,classic,123
      2,"a comma, is in here",test data 1,345
      3,",a comma, is in here",test data 2,346
      4,"a comma, is in here,",test data 3,347
      5,"a comma, is in here,","test data 4
      with a newline","347"
      6,hello world2.,classic,123
      

      【讨论】:

      • An answer by LCC 指出,这也会删除包含行分隔符的单元格的引号 \r\n
      • 编辑答案以包含来自@LCC 的建议。
      【解决方案5】:

      这与接受的答案非常相似,但它有助于防止不必要地删除“真实”引号。

      $delimiter = ','
      Get-Process | ConvertTo-Csv -Delimiter $delimiter -NoTypeInformation | foreach { $_ -replace '^"','' -replace "`"$delimiter`"",$delimiter -replace '"$','' }
      

      这将执行以下操作:

      • 删除行首的引号
      • 删除行尾的引号
      • 将包含分隔符的引号替换为单独的分隔符。

      因此,出错的唯一方法是其中一个值实际上不仅包含引号,而且特别包含引号 - 分隔符 - 引号序列,希望这种情况很少见。

      【讨论】:

      • 如果您正在使用的数据因包含分隔符而被引用,则此方法不起作用。
      【解决方案6】:

      文件生成后,就可以运行了

      set-content FILENAME.csv ((get-content FILENAME.csv) -replace '"')
      

      【讨论】:

      • 这应该是答案。非常感谢你
      • 如果我有一个 CSV 行,其中包含三个参数,例如 "123", "Sanchez, Rick", "Scientist",这会将其转换为四个参数。后续输入过程将无法正确导入。
      • @Tony 不是 4 个参数吗?你得到哪个错误?
      • @Tiago 是三个:ID、姓名和职位。名称恰好在其文本中包含一个逗号分隔符。假设职位是“科学、技术和物流副总裁”。去掉引号将那一列变成了三列。
      • @Tony 您可以在删除双引号之前将双引号之间的逗号替换为任何其他字符,例如连字符 (-)。 There's a solution here 暗示了这一点,$Pattern = '(?&lt;!"".+),(?!.+"")' $Text = '"abc, 123"' $Text -replace $Pattern , '-'
      【解决方案7】:

      根据您的 CSV 数据的病态(或“功能齐全”)程度,已发布的解决方案之一已经可以使用。

      Kory Gill 发布的解决方案几乎是完美的 - 唯一剩下的问题是包含行分隔符 \r\n 的单元格也会删除引号,这会导致许多工具出现问题。

      解决方案是在字符类表达式中添加换行符:

      $fixedData = $quotedData | % {$_ -replace  `
      '\G(?<start>^|,)(("(?<output>[^,"\n]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$)))' `
      ,'${start}${output}'}
      

      【讨论】:

        【解决方案8】:

        我写这个是为了我的需要:

        function ConvertTo-Delimited {
        
            [CmdletBinding()]
            param(
                [Parameter(ValueFromPipeline=$true,Mandatory=$true)]
                [psobject[]]$InputObject,
                [string]$Delimiter='|',
                [switch]$ExcludeHeader
            )
            Begin {
        
                if ( $ExcludeHeader -eq $false ) {
                    @(
                        $InputObject[0].PsObject.Properties | `
                        Select-Object -ExpandProperty Name
                    ) -Join $Delimiter          
                }
        
            }
            Process {
        
                foreach ($item in $InputObject) {
                    @(
                        $item.PsObject.Properties | `
                        Select-Object Value | `
                        ForEach-Object { 
                            if ( $null -ne $_.Value ) {$_.Value.ToString()} 
                            else {''} 
                        }
                    ) -Join $Delimiter
                }
        
            }
            End {}
        
        }
        

        用法:

        $Data = @(
            [PSCustomObject]@{
                A = $null
                B = Get-Date
                C = $null
            }
            [PSCustomObject]@{
                A = 1
                B = Get-Date
                C = 'Lorem'
            }
            [PSCustomObject]@{
                A = 2
                B = Get-Date
                C = 'Ipsum'
            }
            [PSCustomObject]@{
                A = 3
                B = $null
                C = 'Lorem Ipsum'
            }
        )
        
        # with headers
        PS> ConvertTo-Delimited $Data
        A|B|C
        1|7/17/19 9:07:23 PM|Lorem
        2|7/17/19 9:07:23 PM|Ipsum
        ||
        
        # without headers
        PS> ConvertTo-Delimited $Data -ExcludeHeader
        1|7/17/19 9:08:19 PM|Lorem
        2|7/17/19 9:08:19 PM|Ipsum
        ||
        

        【讨论】:

          【解决方案9】:

          这是另一种方法:

          Get-Process | ConvertTo-Csv -NoTypeInformation -Delimiter "," | 
              foreach { $_ -replace '^"|"$|"(?=,)|(?<=,)"','' }
          

          这会将每行中的匹配项替换为空字符串。分解上面的正则表达式:

          • | 就像一个 OR,用于联合以下 4 个子正则表达式
          • ^" 匹配行首的引号
          • "$ 匹配行尾的引号
          • "(?=,) 匹配后跟逗号的引号
          • (?&lt;=,)" 匹配前面紧跟逗号的引号

          【讨论】:

            【解决方案10】:

            我发现 Kory 的答案不适用于原始字符串连续包含多个空白字段的情况。 IE。 "ABC",,"0" 很好,但 "ABC",,,"0" 处理不当。它停止替换“,,”之后的引号。我通过在第一个参数的末尾添加“|(?&lt;output&gt;)”来修复它,如下所示:

            % {$_ -replace  `
                '\G(?<start>^|,)(("(?<output>[^,"]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$))|(?<output>))', `
                '${start}${output}'}
            

            【讨论】:

            • 很好,这可以处理我的数据。
            【解决方案11】:

            我没有花太多时间寻找删除引号。但是,这里有一个解决方法。

            get-process | Export-Csv -NoTypeInformation -Verbose -Path $env:temp\test.csv
            $csv = Import-Csv -Path $env:temp\test.csv
            

            这是一个快速的解决方法,可能有更好的方法来做到这一点。

            【讨论】:

            • 我仍然使用它获得报价。
            • 我不确定解决方法。除了从 OP 问题中的文件中删除引号之外,还有什么其他的吗?
            【解决方案12】:

            JPBlanc 答案的略微修改变体:

            我有一个现有的 csv 文件,如下所示:

            001,002,003
            004,005,006
            

            我只想将第一列和第三列导出到新的 csv 文件。当然我不想要任何引号;-) 可以这样做:

            Import-Csv -Path .\source.csv -Delimiter ',' -Header A,B,C | select A,C | ConvertTo-Csv -NoTypeInformation -Delimiter ',' | % {$_ -replace '"',''} | Out-File -Encoding utf8 .\target.csv
            

            【讨论】:

              【解决方案13】:

              找不到类似问题的答案,所以我在这里发布我找到的内容...

              对于导出为管道分隔,字符串限定符不带引号,请使用以下内容:

              $objtable | convertto-csv -Delimiter "|" -notypeinformation | select -Skip $headers | % { $_ -replace '"\|"', "|"} | % { $_ -replace '""', '"'} | % { $_ -replace "^`"",''} | % { $_ -replace "`"$",''} | out-file "$OutputPath$filename" -fo -en ascii
              

              这是我能想到的唯一可以处理文本中的引号和逗号的东西;尤其是在文本字段的开头或结尾处相邻的引号和逗号之类的内容。

              【讨论】:

                【解决方案14】:

                此函数从管道中获取一个 powershell csv 对象,并像 convertto-csv 一样输出,但不添加引号(除非需要)。

                function convertto-unquotedcsv {
                    param([Parameter(ValueFromPipeline=$true)]$csv, $delimiter=',', [switch]$noheader=$false)
                    begin {
                      $NeedQuotesRex = "($([regex]::escape($delimiter))|[\n\r\t])"
                      if ($noheader) { $names = @($true) } else { $names = @($false) }
                    } 
                    process {
                      $psop = $_.psobject.properties
                      if (-not $names) {
                        $names = $psop.name | % {if ($_ -match $NeedQuotesRex) {'"' + $_ + '"'} else {$_}}
                        $names -join $delimiter   # unquoted csv header
                      }
                      $values = $psop.value | % {if ($_ -match $NeedQuotesRex) {'"' + $_ + '"'} else {$_}}
                      $values -join $delimiter    # unquoted csv line
                    } 
                    end {
                    }
                }
                

                $names 得到一个noteproperty 名称数组,$values 得到一个notepropery 值数组。它采取了那个特殊的步骤来输出标题。进程块一次获取一个 csv 对象。

                这是一个测试运行

                $delimiter = ','; $csvData = @"
                id,string,notes,"points per 1,000",number
                4,"a delimiter$delimiter is in here,","test data 3",1,348
                5,"a comma, is in here,","test data 4`r`nwith a newline",0.5,347
                6,hello world2.,classic,"3,000",123
                "@
                
                $csvdata | convertfrom-csv | sort number | convertto-unquotedcsv -delimiter $delimiter
                
                id,string,notes,"points per 1,000",number
                6,hello world2.,classic,"3,000",123
                5,"a comma, is in here,","test data 4
                with a newline",0.5,347
                4,"a delimiter, is in here,",test data 3,1,348
                

                【讨论】:

                  猜你喜欢
                  • 2019-10-11
                  • 1970-01-01
                  • 2016-05-16
                  • 2021-12-31
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多