【发布时间】:2020-09-29 15:31:00
【问题描述】:
我需要通过删除内联换行符和印刷引号等特殊字符来清理一些 CSV 数据。我觉得我可以使用 Python 或 Unix 实用程序来完成这项工作,但我被困在一个非常普通的 Windows 2012 机器上,所以尽管我缺乏使用 PowerShell v5 的经验,但我还是试了一下。
这是我想要实现的目标:
$InputFile:
"INCIDENT_NUMBER","FIRST_NAME","LAST_NAME","DESCRIPTION"{CRLF}
"00020306","John","Davis","Employee was not dressed appropriately."{CRLF}
"00020307","Brad","Miller","Employee told customer, ""Go shop somewhere else!"""{CRLF}
"00020308","Ted","Jones","Employee told supervisor, “That’s not my job”"{CRLF}
"00020309","Bob","Meyers","Employee did the following:{LF}
• Showed up late{LF}
• Did not complete assignments{LF}
• Left work early"{CRLF}
"00020310","John","Davis","Employee was not dressed appropriately."{CRLF}
$OutputFile:
"INCIDENT_NUMBER","FIRST_NAME","LAST_NAME","DESCRIPTION"{CRLF}
"00020307","Brad","Miller","Employee told customer, ""Go shop somewhere else!"""{CRLF}
"00020308","Ted","Jones","Employee told supervisor, ""That's not my job"""{CRLF}
"00020309","Bob","Meyers","Employee did the following: * Showed up late * Did not complete assignments * Left work early"{CRLF}
"00020310","John","Davis","Employee was not dressed appropriately."{CRLF}
以下代码有效:
(Get-Content $InputFile -Raw) `
-replace '(?<!\x0d)\x0a',' ' `
-replace "[‘’´]","'" `
-replace '[“”]','""' `
-replace "\xa0"," " `
-replace '[•·]','*' | Set-Content $OutputFile -Encoding ASCII
但是,我正在处理的实际数据是一个 4GB 的文件,其中包含超过一百万行。 Get-Content -Raw 内存不足。我试过Get-Content -ReadCount 10000,但这会删除所有换行符,大概是因为它按行读取。
更多谷歌搜索将我带到 Import-Csv,我从 here 获得:
Import-Csv $InputFile | ForEach {
$_.notes = $_.notes -replace '(?<!\x0d)\x0a',' '
$_
} | Export-Csv $OutputFile -NoTypeInformation -Encoding ASCII
但我的对象上似乎没有 notes 属性:
Exception setting "notes": "The property 'notes' cannot be found on this object. Verify that the property exists and can be set."
At C:\convert.ps1:53 char:5
+ $_.notes= $_.notes -replace '(?<!\x0d)\x0a',' '
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
我找到了另一个使用 Value 属性的示例,但我得到了同样的错误。
我尝试在每个对象上运行 Get-Member,看起来它是根据文件中的标头分配属性,就像我可以使用 $_.DESCRIPTION 获得它一样,但我不知道足够的 PowerShell 来运行所有属性的替换:(
请帮忙?谢谢!
更新:
我最终放弃了 PS 并在 AutoIT 中编码。它不是很好,而且维护起来会更加困难,尤其是在 2.5 年没有新版本的情况下。但它可以工作,并且可以在 4 分钟内处理 prod 文件。
不幸的是,我也不能轻松地键入 LF,所以我最终采用基于 ^"[^",] 的逻辑创建新行(行以引号开头,第二个字符不是引号或逗号) .
这是 AutoIT 代码:
#include <FileConstants.au3>
If $CmdLine[0] <> 2 Then
ConsoleWriteError("Error in parameters" & @CRLF)
Exit 1
EndIf
Local Const $sInputFilePath = $CmdLine[1]
Local Const $sOutputFilePath = $CmdLine[2]
ConsoleWrite("Input file: " & $sInputFilePath & @CRLF)
ConsoleWrite("Output file: " & $sOutputFilePath & @CRLF)
ConsoleWrite("***** WARNING *****" & @CRLF)
ConsoleWrite($sOutputFilePath & " is being OVERWRITTEN!" & @CRLF & @CRLF)
Local $bFirstLine = True
Local $hInputFile = FileOpen($sInputFilePath, $FO_ANSI)
If $hInputFile = -1 Then
ConsoleWriteError("An error occurred when reading the file.")
Exit 1
EndIf
Local $hOutputFile = FileOpen($sOutputFilePath, $FO_OVERWRITE + $FO_ANSI)
If $hOutputFile = -1 Then
ConsoleWriteError"An error occurred when opening the output file.")
Exit 1
EndIf
ConsoleWrite("Processing..." &@CRLF)
While True
$sLine = FileReadLine($hInputFile)
If @error = -1 Then ExitLoop
;Replace typographic single quotes and backtick with apostrophe
$sLine = StringRegExpReplace($sLine, "[‘’´]","'")
;Replace typographic double quotes with normal quote (doubled for in-field CSV)
$sLine = StringRegExpReplace($sLine, '[“”]','""')
;Replace bullet and middot with asterisk
$sLine = StringRegExpReplace($sLine, '[•·]','*')
;Replace non-breaking space (0xA0) and delete (0x7F) with space
$sLine = StringRegExpReplace($sLine, "[\xa0\x7f]"," ")
If $bFirstLine = False Then
If StringRegExp($sLine,'^"[^",]') Then
$sLine = @CRLF & $sLine
Else
$sLine = " " & $sLine
EndIf
Else
$bFirstLine = False
EndIf
FileWrite($hOutputFile, $sLine)
WEnd
ConsoleWrite("Done!" &@CRLF)
FileClose($hInputFile)
FileClose($hOutputFile)
【问题讨论】:
-
只需将
$_.notes替换为$_.DESCRIPTION,就可以了 -
谢谢!问题是实际数据每行包含 600 个字段,其中数百个可能包含换行符和特殊字符。
-
看到这个:Reading large text files with Powershell,你可以用简洁的正则表达式或模式替换所有这些 -replace。例如 "'(?
-
@postanote 感谢您的链接!这实际上是我找到删除所有换行符的 -ReadCount 选项的地方。
标签: powershell csv newline