2017-09-14 63 views
1

我与以下内容的源的文件:移调行列的PowerShell

 
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

你总是有数据只有一行?即每隔第二行总是内容,还是可以保存多行值? – arco444

+0

@ arco444是始终有一行数据,没有多行值。 – MaheshMohan

回答

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 '|' 
} 
+0

嗨@Ansgar是的,我也收到相同的ArrayIndexoutofBound异常。 – MaheshMohan

+0

该例外是由于复制/粘贴错误。我忘了把'$ row [$ i] = $ arr [$ n + 1]'改成'$ row + = $ arr [$ n + 1]'。至于@MaheshMohan的空格,请说明你的输入文件是否实际上有尾随空格。我假设你在上一个问题中为每个行添加了2个尾部空格用于格式化目的。 –

+0

@Ansgar是的你说得对。我增加了格式化的空间。 – MaheshMohan

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下一次迭代。

一旦我们收集了所有我们需要检查是否有任何缺失字段值的信息,所以我们从每个散列中获取最高数字,从0开始循环,并用空字符串填充任何缺失值。

一旦完成,您可以迭代数组,按字段数对每个散列进行排序并加入值。

+0

Hi @ arco444。这很好解释。谢谢!我试着用下面的文件内容设置上面的代码,它没有工作。输出变得混乱,并且输出文件中的源文件内容也缺少一些数据。 – MaheshMohan

+0

这是根据您在问题中提供的输入进行编写和测试的。如果您使用的实际文件不同,我不能保证它会起作用。但是你现在有了代码,所以你应该可以修改它以适应;) – arco444

+0

非常感谢你的代码!根据我的变化,我正在编辑你的代码,同时Ansgar回应。再次非常感谢! – MaheshMohan