Powershell 如何将大型垂直文本文件转换并解析为带有标题的CSV文件?
我有一个大文本文件(*.txt),格式如下:Powershell 如何将大型垂直文本文件转换并解析为带有标题的CSV文件?,powershell,csv,scripting,Powershell,Csv,Scripting,我有一个大文本文件(*.txt),格式如下: ; KEY 123456 ; Any Company LLC ; 123 Main St, Anytown, USA SEC1 = xxxxxxxxxxxxxxxxxxxxx SEC2 = xxxxxxxxxxxxxxxxxxxxx SEC3 = xxxxxxxxxxxxxxxxxxxxx SEC4 = xxxxxxxxxxxxxxxxxxxxx SEC5 = xxxxxxxxxxxxxxxxxxxxx SEC6 = xxxxxxxxxxxxxxx
; KEY 123456
; Any Company LLC
; 123 Main St, Anytown, USA
SEC1 = xxxxxxxxxxxxxxxxxxxxx
SEC2 = xxxxxxxxxxxxxxxxxxxxx
SEC3 = xxxxxxxxxxxxxxxxxxxxx
SEC4 = xxxxxxxxxxxxxxxxxxxxx
SEC5 = xxxxxxxxxxxxxxxxxxxxx
SEC6 = xxxxxxxxxxxxxxxxxxxxx
这是重复约350-400键。这些是搭扣钥匙和与之相关的SEC代码。我试图将此文件解析为一个CSV文件,其中包含KEY和SEC1-SEC6作为标题,并填充行。这是我正在尝试的格式:
KEY,SEC1,SEC2,SEC3,SEC4,SEC5,SEC6
123456,xxxxxxxxxx,xxxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx
456789,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx,xxxxxxxxxx
我已经能够使用文本文件(我的测试文件)中的一个键将脚本导出到CSV,但是当我尝试在完整列表中运行它时,它只导出最后一个键和秒代码
$keysheet = '.\AllKeys.txt'
$holdarr = @{}
Get-Content $keysheet | ForEach-Object {
if ($_ -match "KEY") {
$key, $value = $_.TrimStart("; ") -split " "
$holdarr[$key] = $value }
elseif ($_ -match "SEC") {
$key, $value = $_ -split " = "
$holdarr[$key] = $value }
}
$hash = New-Object PSObject -Property $holdarr
$hash | Export-Csv -Path '.\allsec.csv' -NoTypeInformation
当我在完整列表中运行它时,它还添加了两个额外的列,这些列看起来像属性而不是值
如果您有任何帮助,我们将不胜感激
谢谢。这将是一种方法
& {
$entry = $null
switch -Regex -File '.\AllKeys.txt' {
"KEY" {
if ($entry ) {
[PSCustomObject]$entry
}
$entry = @{}
$key, $value = $_.TrimStart("; ") -split " "
$entry[$key] = [int]$value
}
"SEC" {
$key, $value = $_ -split " = "
$entry[$key] = $value
}
}
[PSCustomObject]$entry
} | sort KEY | select KEY,SEC1,SEC2,SEC3,SEC4,SEC5,SEC6 |
Export-Csv -Path '.\allsec.csv' -NoTypeInformation
以下是我建议的方法:
$output = switch -Regex -File './AllKeys.txt' {
'^; KEY (?<key>\d+)' {
if ($o) {
[pscustomobject]$o
}
$o = @{
KEY = $Matches['key']
}
}
'^(?<sec>SEC.*?)\s' {
$o[$Matches['sec']] = ($_ | ConvertFrom-StringData)[$Matches['sec']]
}
default {
Write-Warning -Message "No match found: $_"
}
}
# catch the last object
$output += [pscustomobject]$o
$output | Export-Csv -Path './some.csv' -NoTypeInformation
$output=switch-Regex-File'./AllKeys.txt'{
“^;键(?\d+)”{
如有的话($o){
[pscustomobject]$o
}
$o=@{
KEY=$Matches['KEY']
}
}
“^(?秒。*?)\s”{
$o[$Matches['sec']=($|从StringData转换)[$Matches['sec']]
}
违约{
写入警告-消息“未找到匹配项:$\
}
}
#抓住最后一个物体
$output+=[pscustomobject]$o
$output | Export Csv-Path'/some.Csv'-notype信息
让我们充分利用
将包含一个或多个键和值对的字符串转换为哈希表
所以我们要做的是
convertfromstringdata
以创建哈希表现在使用
将CSV导出到您的内容中 检查ConvertFrom-StringData
cmdlet。当你尝试解析Key=Value
对时,它会让你的生活变得更轻松。总是有一组正好6秒的行吗?@Matt Yes。总是有整整6秒的行。你的$entry=$null
在头部是不必要的(除非它是在scriptblock之外定义的,但我认为应该使用$local:
或$private:
修饰符)@1不可纠正的是,语言可能不需要它,但我认为添加它仍然是一种很好的风格。@marsze这很接近。标题行正在导出,但所有其他行都是空的,只有分隔符。@Harlan我做了一些编辑。你用的是最新版本吗?此外,请在导出之前检查输出。查看返回空值的确切位置。我用你的数据测试了这个,它应该可以正常工作。@marsze它取决于我使用的PS版本。最初我使用的是2.0。当我在一台装有PS5的机器上试用它时,它就像一个魔咒。唯一的变化是,我必须去掉[int]这一铸造键值的元素。不知道为什么。错误是它无法从System.Object[]
转换到System.Int32
。谢谢除了删除与sec行匹配的绒毛行之外,word也可以这样做。我的方法将整个块转换为键值对,这样就可以在一个快照中处理它。看起来开销很大,只能使用convertfromstringdata
。我看不出有什么好处。无论如何,它工作得很好,所以+1
$path = "c:\temp\keys.txt"
# Split the file into its key/sec collections. Drop any black entries created in the split
(Get-Content -Raw $path) -split ";\s+KEY\s+" | Where-Object{-not [string]::IsNullOrWhiteSpace($_)} | ForEach-Object{
# Split the block into lines again
$lines = $_ -split "`r`n" | Where-Object{$_ -notmatch "^;" -and -not [string]::IsNullOrWhiteSpace($_)}
# Edit the first line so we have a full block of key=value pairs.
$lines[0] = "key=$($lines[0])"
# Use ConvertFrom-StringData to do the leg work after we join the lines back as a single string.
[pscustomobject](($lines -join "`r`n") | ConvertFrom-StringData)
} |
# Cannot guarentee column order so we force it with this select statement.
Select-Object KEY,SEC1,SEC2,SEC3,SEC4,SEC5,SEC6