Reputation: 29
I have a txt file like this but I need to add a tab if there are 7 or less characters (including the wrapped double quotes) in EACH of the entries in the LIST column and then replace into file so it formats pretty (this file can only be txt, in the format it currently is in, etc):
Current
List: ID:
"izzak" "QWERTY654POI"
"swortz23" "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est" "QWERTY654POI"
"muffin0" "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle" "QWE78Y654POI"
"fie4lder" "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart" "11ERTY654POI"
"bbs3" "QWERTY654POI"
Needs to look like this:
List: ID:
"izzak" "QWERTY654POI"
"swortz23" "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est" "QWERTY654POI"
"muffin0" "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle" "QWE78Y654POI"
"fie4lder" "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart" "11ERTY654POI"
"bbs3" "QWERTY654POI"
$where = Get-Content C:\Users\me\Desktop\info.txt
#pull any text on each line before a tab (gets first column if wrapped in double quotes)
$pattern = '(".*")(?:\t)'
$arrayoutput = (Get-Content -Path "C:\Users\me\Desktop\info.txt" | Select-String $pattern -AllMatches | ForEach-Object { $_.Matches.Value }).Trim()
foreach ($product in $arrayoutput) {
if ($product.length -le 7) {
$addtab = "$product"+"`t"
$endresult = $where.replace($product, $addtab)
}
}
$endresult | Set-Content -Path "C:\Users\me\Desktop\info.txt"
Results look like this (where the last line gets tabbed but no others):
"izzak" "QWERTY654POI"
"swortz23" "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est" "QWERTY654POI"
"muffin0" "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle" "QWE78Y654POI"
"fie4lder" "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart" "11ERTY654POI"
"bbs3" "QWERTY654POI"
My code will only add a tab to the LAST entry if there are multiple entries in the LIST column less than or equal to 7 (counting the double quotes around it; 5 otherwise).
Anyone have any thoughts on this or how to iterate through each array entry and then replace the old entry with the new?
EDIT: Every line is single tab
delimited between the 2 columns.
Upvotes: 0
Views: 257
Reputation: 13567
If it's only processing the last line, then this means we're not saving what we're doing in the for-each loop as we go.
Since it's not being saved as we go, then only the last line to be processed is going to be updated.
Let's look at your forEach
.
foreach ($product in $arrayoutput) {
if ($product.length -le 7) {
$addtab = "$product"+"`t"
$endresult = $where.replace($product, $addtab)
}
}
This is resaving $endResult
every time, and saving it with the value of $where
, when you replace one value for another, that means each time you go through this foreach you replace one line and then you do it again the next time, and the next.
You're not preserving the changes because you resave $endResult
with the one change operation against $where
each time. This is the bug.
Instead, we can make it work with just two changes. First, at the start of the script we'll copy over all of $where
which is the original, unedited text file, and store that as $endResult
. Then, we modify the loop to just edit $endResult
effectively fixing the file line by line as we progress through the loop.
#store the unedited file as `$endResult`
$endresult = $where
foreach ($product in $arrayoutput) {
if ($product.length -le 7) {
$addtab = "$product"+"`t"
#as we progress through the loop, we are cleaning up the endresult file line by line
$endresult = $endresult.replace($product, $addtab)
}
}
This will update $endResult
as you go, preserving the previous edits. I don't have the same source file as you to recreate this, but it should work.
Upvotes: 1
Reputation: 187
By using hashtable, it's very useful and may come handy in future work
$clear = (Get-content "$path\source.txt").Split(' ') | % { $_.Split(' ')} | ? {$_ -notcontains [string]::Empty}; $hash = @{}; For($i = 0;$i -lt $clear.count; $i=$i+2){$hash.Add($clear[$i], $clear[$i+1])}; $hash >> $path\result.txt
result of txt file:
Name Value
---- -----
"urquhart" "11ERTY654POI"
"campingou" "QWERTY454POI"
"muffin0" "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle" "QWE78Y654POI"
"izzak" "QWERTY654POI"
"bbs3" "QWERTY654POI"
"fie4lder" "QWERTY654POI"
"swortz23" "00ERTY654POI"
"dark1est" "QWERTY654POI"
"67532" "QWERTY654POI"
Of couse now you can edit this table as you wish, for example delete excess entries of spaces by using Remove method for example
([string[]](Get-Content $path\result.txt)) | % {$_.Remove(10,20)}
Or replace Headers and save it again in txt file
([string[]](Get-Content $path\result.txt)) | % {$_.Replace("Name", "List:")} | % {$_.Replace("Value", "Id:")}
Upvotes: 1
Reputation: 61253
A TAB character is of variable length. That depends on the application that is reading the file at that moment, so I would opt for using space characters to align the strings.
This will always look right, provided you use a mono-spaced font.
(In HTML you can embed the result in <pre>..</pre>
tags to ensure that).
# create two List objects for the left and right parts of each string
$left = [System.Collections.Generic.List[string]]::new()
$right = [System.Collections.Generic.List[string]]::new()
Get-Content -Path 'D:\Test\file.txt' | ForEach-Object {
$l, $r = $_ -split '\s+', 2
$left.Add($l)
$right.Add($r)
}
# calculate the max length of the left strings under 'List'
$maxpad = ($left | Measure-Object -Property Length -Maximum).Maximum + 1 # + 1 for padding
# now loop through the lists and output padded lines
$result = for ($i = 0; $i -lt $left.Count; $i++) {
"{0,-$maxpad}{1}" -f $left[$i], $right[$i]
# or use
#'{0}{1}' -f $left[$i].PadRight($maxpad), $right[$i]
}
$result
Output:
List: ID:
"izzak" "QWERTY654POI"
"swortz23" "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est" "QWERTY654POI"
"muffin0" "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle" "QWE78Y654POI"
"fie4lder" "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart" "11ERTY654POI"
"bbs3" "QWERTY654POI"
Upvotes: 1