我有一个包含以下内容的源文件:
0 ABC 1 181.12 2 05/07/16 4 Im4thData 5 hello -1 0 XYZ 1 1333.21 2 02/02/16 3 Im3rdData 5 world -1 ...
' -1'在上面的列表中是记录分隔符,它指示下一条记录的开始。 0,1,2,3,4,5等与列标识符(或列名称)类似。
这是我的代码。
$txt = Get-Content 'C:myfile.txt' | Out-String
$txt -split '(?m)^-1\r?\n' | ForEach-Object {
$arr = $_ -split '\r?\n'
$indexes = 1..$($arr.Count - 1) | Where-Object { ($_ % 2) -ne 0 }
$arr[$indexes] -join '|'
}
上面的代码创建如下输出:
ABC|181.12|05/07/16|Im4thData|hello XYZ|1333.21|02/02/16|Im3rdData|World ...
但我需要输出如下。如果源文件中没有列,则其行数据应在输出文件中具有如下所示的空白管道线(||
)。请告知代码中所需的更改。
ABC|181.12|05/07/16||Im4thData|hello ← There is no 3rd column in the source file. so blank pipe line (||). XYZ|1333.21|02/02/16|Im3rdData||World ← There is no 4th column column in the source file. so blank pipe line (||). ...
答案 0 :(得分:1)
需要相当多的处理。可能有一种更有效的方法可以做到这一点,但下面的确有效。
$c = Get-Content ".\file.txt"
$rdata = @{}
$data = @()
$i = 0
# Parse the file into an array of key-value pairs
while ($i -lt $c.count) {
if($c[$i].trim() -eq '-1') {
$data += ,$rdata
$rdata = @{}
$i++
continue
}
$field = $c[$i].trim()
$value = $c[++$i].trim()
$rdata[$field] = $value
$i++
}
# Check if there are any missing values between 0 and the highest value and set to empty string if so
foreach ($row in $data) {
$top = [int]$($row.GetEnumerator() | Sort-Object Name -descending | select -First 1 -ExpandProperty Name)
for($i = 0; $i -lt $top; $i++) {
if ($row["$i"] -eq $null) {
$row["$i"] = ""
}
}
}
# Sort each hash by field order and join with pipe
$data | ForEach-Object { ($_.GetEnumerator() | Sort-Object -property Name | Select-Object -ExpandProperty Value) -join '|' }
在while
循环中,我们只是迭代文件的每一行。字段编号值由值1分隔,因此每次迭代我们都将两个值都加到哈希值中。
如果我们遇到-1
,那么我们知道我们有一个记录分隔符,所以将哈希值添加到数组中,重置它,将计数器碰到下一个记录,然后continue
到下一次迭代。< / p>
一旦我们收集了所有我们需要检查是否有任何缺失字段值的内容,我们就会从每个散列中获取最高数字,从0
循环遍历它并填充任何缺少的值为空串。
完成后,您可以迭代数组,按字段编号对每个哈希值进行排序并加入值。
答案 1 :(得分:1)
如果您事先知道最大列数,可以执行以下操作:
$cols = 6
$txt = Get-Content 'C:myfile.txt' | Out-String
$txt -split '(?m)^-1\r?\n' | ForEach-Object {
# initialize array of required size
$row = ,$null * $cols
$arr = $_ -split '\r?\n'
for ($n = 0; $n -lt $arr.Count; $n += 2) {
$i = [int]$arr[$n]
$row[$i] = $arr[$n+1]
}
$row -join '|'
}
否则你可以这样做:
$txt = Get-Content 'C:myfile.txt' | Out-String
$txt -split '(?m)^-1\r?\n' | ForEach-Object {
# create empty array
$row = @()
$arr = $_ -split '\r?\n'
$k = 0
for ($n = 0; $n -lt $arr.Count; $n += 2) {
$i = [int]$arr[$n]
# if index from record ($i) is greater than current index ($k) append
# required number of empty fields
for ($j = $k; $j -lt $i-1; $j++) { $row += $null }
$row += $arr[$n+1]
$k = $i
}
$row -join '|'
}