2017-09-14 61 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