如何删除Excel中的多余行

时间:2016-05-25 06:26:52

标签: excel powershell

我试图清理我的数据。我已经看到了关于这个主题的一些内容。我已经关注并应用了这些示例,但我的脚本似乎出现了问题。

Screenshot of a sample Excel file I was trying to clean up

我想要做的是删除整行。 column为null。当我运行我的脚本时,只有一半的行没有空。列已删除。在完全删除所有空行之前,我必须多次运行我的脚本。删除PowerShell中的行是否有限制,或者我遗漏了什么?这是我的剧本:

#cleanup
$max = $sheet.UsedRange.Rows.Count

for ($i = 6; $i -le $max; $i++) {
    if ($sheet.Cells.Item($i, 1).Text -eq "") {
        $Range = $sheet.Cells.Item($i, 1).EntireRow
        $Range.Delete()
    }
}

更新 为了解决删除问题,我添加了$ i = $ i - 1 ..现在我必须找到一种方法来停止循环

 for ($i = 6; $i -le $row; $i++) {
    If ($Sheet.Cells.Item($i, 1).text -eq "") {
        $Range = $Sheet.Cells.Item($i, 1).EntireRow
        [void]$Range.Delete()
        $i = $i - 1
    } 
} 

2 个答案:

答案 0 :(得分:1)

如果您要删除"转发"每次删除行时,for循环都会跳过一行。如果删除行n,则前一行n + 1现在变为行n。但是,由于索引会自动递增,因此您将在下一次迭代中转到新行n + 1(前一行n + 2),从而跳过前一行n + 1(新行n)。

示例:

考虑使用这样的表(第一列是行号):

  ┌──────────
1 │ A
  ├──────────
2 │ B
  ├──────────
3 │ C
  ├──────────

for这样的循环:

for ($i=1; $i -le 2; $i++) {
  $sheet.Rows.Item($i).Delete()
}

在第一次迭代中,$i的值为1,因此它指向第1行:

  ┏━━━━━━━━━━
1 ┃ A
  ┡━━━━━━━━━━
2 │ B
  ├──────────
3 │ C
  ├──────────

通过删除该行,后续行向上移动,因此表格变为如此(在第一次迭代结束时):

  ┌──────────
1 │ B
  ├──────────
2 │ C
  ├──────────

第二行现在已成为第一行。但是,当进入下一次迭代时,变量$i会增加到2,所以它现在指向第2行(前第三行):

  ┌──────────
1 │ B           ← skipped this row
  ┢━━━━━━━━━━
2 ┃ C
  ┡━━━━━━━━━━

你可以从底行开始回到前面来避免这种影响:

$max = $sheet.UsedRange.Rows.Count
for ($i = $max; $i -ge 6; $i--) {
    if ($sheet.Cells.Item($i, 1).Text -eq '') {
        $Range = $sheet.Rows.Item($i).Delete()
    }
}

请注意.UsedRange.Rows.Count不一定会为您提供最后一行的编号。如果在第一个使用的行之前有空行,则需要将它们的数字作为偏移量添加到使用范围中的行数:

$max = $sheet.UsedRange.Rows.Count + $sheet.UsedRange.Row - 1

答案 1 :(得分:0)

为了解决上面的问题,我使用了一个向后的for循环而不是一个forward for循环。感谢@RonRosenfeld的想法.. @AngarWiechers给出了一个非常有见地的解释为什么使用正向循环是不合适的。他的回答只需要一点调整。设置$ i -ge 6仍然不是后向循环的保证终点。为了停止循环,我添加了一个else语句,当$ Sheet.Cells.Item($ i,1).text不再等于“null”时,它将设置$ i = 0.这将结束向后循环。

 #cleanup
$max = $sheet.UsedRange.Rows.Count


for ($i = $max; $i -ge 0; $i--) {
    If ($Sheet.Cells.Item($i, 1).text -eq "") {
        $Range = $Sheet.Cells.Item($i, 1).EntireRow
        [void]$Range.Delete()
        echo $i
    } 
    Else {$i = 0}
}