PowerShell 替换循环如此接近但仅影响数组中的最后一个对象

问题描述

我有一个这样的 txt 文件,但如果 LIST 列中的每个条目中有 7 个或更少的字符(包括包裹的双引号),我需要添加一个制表符,然后将其替换到文件中,使其格式漂亮(此文件只能是 txt、当前格式等):

当前

List:       ID:

"izzak" "QWERTY654POI"
"swortz23"  "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est"  "QWERTY654POI"
"muffin0"   "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle"   "QWE78Y654POI"
"fie4lder"  "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart"  "11ERTY654POI"
"bbs3"  "QWERTY654POI"

需要看起来像这样:

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"

结果看起来像这样(最后一行被制表而没有其他行):

"izzak" "QWERTY654POI"
"swortz23"  "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est"  "QWERTY654POI"
"muffin0"   "QWERTY654POI"
"parly" "25ERTY654POI"
"ggghsle"   "QWE78Y654POI"
"fie4lder"  "QWERTY654POI"
"67532" "QWERTY654POI"
"urquhart"  "11ERTY654POI"
"bbs3"      "QWERTY654POI"

如果 LIST 列中有多个条目小于或等于 7(计算它周围的双引号;否则为 5),我的代码只会向 LAST 条目添加一个制表符。

有没有人对此有任何想法或如何遍历每个数组条目,然后用新条目替换旧条目?

编辑:每一行都是单行 tab 分隔在 2 列之间。

解决方法

如果它只处理最后一行,那么这意味着我们不会在进行时保存我们在 for-each 循环中所做的事情。

由于它没有被保存,所以只有最后一行要处理的会被更新。
让我们看看您的 forEach

foreach ($product in $arrayoutput) {
   if ($product.length -le 7) {
    $addtab = "$product"+"`t"
    $endresult = $where.replace($product,$addtab)
    }
 }

这是每次都重新保存$endResult,并将其保存为$where的值,当您将一个值替换为另一个值时,这意味着每次执行此foreach时都会替换一行,然后你下次再做一次,下一次。

您没有保留更改,因为您每次都使用针对 $endResult 的一个更改操作重新保存 $where这是错误。

相反,我们只需进行两次更改即可使其工作。首先,在脚本开始时,我们将复制所有未经编辑的原始文本文件 $where,并将其存储为 $endResult。然后,我们修改循环以仅编辑 $endResult,在循环过程中逐行有效地修复文件。

#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)
    }
 }

这会在您进行时更新 $endResult,保留之前的编辑。我没有与您相同的源文件来重新创建它,但它应该可以工作。

,

TAB 字符是可变长度的。这取决于当时正在读取文件的应用程序,因此我会选择使用空格字符来对齐字符串。 这看起来总是正确的,前提是您使用等宽字体
(在 HTML 中,您可以将结果嵌入 <pre>..</pre> 标签以确保)。

# 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

输出:

List:       ID:
            
"izzak"     "QWERTY654POI"
"swortz23"  "00ERTY654POI"
"campingou" "QWERTY454POI"
"dark1est"  "QWERTY654POI"
"muffin0"   "QWERTY654POI"
"parly"     "25ERTY654POI"
"ggghsle"   "QWE78Y654POI"
"fie4lder"  "QWERTY654POI"
"67532"     "QWERTY654POI"
"urquhart"  "11ERTY654POI"
"bbs3"      "QWERTY654POI"
,

通过使用哈希表,它非常有用,可能会在以后的工作中派上用场

  $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

txt 文件的结果:

Name                           Value
----                           -----
"urquhart"                     "11ERTY654POI"
"campingou"                    "QWERTY454POI"
"muffin0"                      "QWERTY654POI"
"parly"                        "25ERTY654POI"
"ggghsle"                      "QWE78Y654POI"
"izzak"                        "QWERTY654POI"
"bbs3"                         "QWERTY654POI"
"fie4lder"                     "QWERTY654POI"
"swortz23"                     "00ERTY654POI"
"dark1est"                     "QWERTY654POI"
"67532"                        "QWERTY654POI"

当然,现在您可以随意编辑此表,例如使用 Remove 方法删除多余的空格条目

([string[]](Get-Content $path\result.txt)) | % {$_.Remove(10,20)}

或者替换Headers并再次保存在txt文件中

([string[]](Get-Content $path\result.txt)) | % {$_.Replace("Name","List:")} |  % {$_.Replace("Value","Id:")}