Ответ 1
Вот способ удаления кавычек
get-process | convertto-csv -NoTypeInformation -Delimiter "," | % {$_ -replace '"',''}
Но он имеет серьезный недостаток, если один из элементов содержит "
, он будет удален!
Я использую ConvertTo-Csv
для получения выхода с разделителями-запятыми
get-process | convertto-csv -NoTypeInformation -Delimiter ","
Он выводится следующим образом:
"__NounName","Name","Handles","VM","WS",".....
Однако я хотел бы получить вывод без кавычек, например
__NounName,Name,Handles,VM,WS....
Вот способ удаления кавычек
get-process | convertto-csv -NoTypeInformation -Delimiter "," | % {$_ -replace '"',''}
Но он имеет серьезный недостаток, если один из элементов содержит "
, он будет удален!
Сегодня я работал над столом и думал об этом же самом вопросе, когда я просматривал файл CSV в блокноте и решил посмотреть, что придумали другие. Кажется, многие слишком усложнили решение.
Вот действительно простой способ удалить кавычки из файла CSV, созданного командлетом Export-Csv в PowerShell.
Создайте файл TEST.csv со следующими данными.
"ID", "Имя", "государство"
"5", "Стефани", "Аризона"
"4", "Мелани", "Орегон"
"2", "Кэти", "Техас"
"8", "Стив", "Айдахо"
"9", "Долли", "Теннесси"
Сохранить как: TEST.csv
Хранить содержимое файла в переменной $ Test $Test = Get-Content.\TEST.csv
Загрузите переменную $ Test, чтобы увидеть результаты командлета get-content $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
Это довольно похоже на принятый ответ, но помогает предотвратить нежелательное удаление "реальных" котировок.
$delimiter = ','
Get-Process | ConvertTo-Csv -Delimiter $delimiter -NoTypeInformation | foreach { $_ -replace '^"','' -replace "`"$delimiter`"",$delimiter -replace '"$','' }
Это сделает следующее:
Следовательно, единственный способ, которым это пошло бы неправильно, - это то, что одно из значений фактически содержит не только кавычки, но, в частности, последовательность цитат-разделителей-кавычек, которые, надеюсь, должны быть довольно необычными.
Я столкнулся с этой проблемой, нашел этот вопрос, но не был удовлетворен ответами, потому что они все, кажется, страдают, если данные, которые вы используете, содержат разделитель, который должен оставаться в кавычках. Избавиться от ненужных двойных кавычек - это хорошо.
Представленное ниже решение, по-видимому, решает эту проблему для общего случая и для всех вариантов, которые могут вызвать проблемы.
Я нашел этот ответ в другом месте, Удаление цитат из CSV, созданного PowerShell, и использовал его для кодирования примера ответа для сообщества SO.
Атрибуция: Кредит на регулярное выражение, 100% идет на Русь Лоськи.
Код в функции, 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
В зависимости от того, насколько патологическими (или "полнофункциональными") являются ваши CSV-данные, одно из опубликованных решений уже будет работать.
Решение, опубликованное Kory Gill, почти идеально - осталась только одна проблема: кавычки удаляются и для ячеек, содержащих разделитель строк \r\n
, что вызывает проблемы во многих инструментах.
Решением является добавление новой строки в выражение класса символов:
$fixedData = $quotedData | % {$_ -replace '
'\G(?<start>^|,)(("(?<output>[^,"\n]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$)))' '
,'${start}${output}'}
Я не потратил много времени на поиск котировок. Но вот обходной путь.
get-process | Export-Csv -NoTypeInformation -Verbose -Path $env:temp\test.csv
$csv = Import-Csv -Path $env:temp\test.csv
Это быстрое обходное решение, и может быть лучший способ сделать это.
Я обнаружил, что ответ Кори не работает для случая, когда исходная строка включала более одного пустого поля в строке. То есть "ABC", "0" было хорошо, но "ABC", "0" не обрабатывалось должным образом. Он прекратил заменять кавычки после ",,". Я установил его, добавив "|(?<output>)
" ближе к концу первого параметра, например:
% {$_ -replace `
'\G(?<start>^|,)(("(?<output>[^,"]*?)"(?=,|$))|(?<output>".*?(?<!")("")*?"(?=,|$))|(?<output>))', `
'${start}${output}'}
Я написал это для моих нужд:
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
||
Хм, у меня на Mac есть предварительный просмотр Powershell 7 preview 1, а у Export-Csv есть опция -UseQuotes, которую вы можете установить на Never. :)