ConvertTo-Csv 输出不带引号

Posted

技术标签:

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

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

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

输出如下:

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

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

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

【问题讨论】:

【参考方案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

【讨论】:

以上是关于ConvertTo-Csv 输出不带引号的主要内容,如果未能解决你的问题,请参考以下文章

(已解决)python向列表添加字符串不带单引号

print()函数与转义字符

NSPredicate,带引号/不带引号

怎样区分JS的函数中参数带引号与不带引号?

将 MySQL 导出为 CSV,一些列带引号,一些不带引号

正则表达式将引号添加到不带引号的 CSV 列