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 = '(?<!"".+),(?!.+"")' $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 个子正则表达式
^"
匹配行首的引号
"$
匹配行尾的引号
"(?=,)
匹配后跟逗号的引号
(?<=,)"
匹配前面紧跟逗号的引号
【讨论】:
【参考方案10】:我发现 Kory 的答案不适用于原始字符串连续包含多个空白字段的情况。 IE。 "ABC",,"0" 很好,但 "ABC",,,"0" 处理不当。它停止替换“,,”之后的引号。我通过在第一个参数的末尾添加“|(?<output>)
”来修复它,如下所示:
% $_ -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 输出不带引号的主要内容,如果未能解决你的问题,请参考以下文章