Powershell 比较未返回正确信息的字符串

Powershell 比较未返回正确信息的字符串,powershell,if-statement,Powershell,If Statement,我们正在使用一个包含许多不同类型报告的文本文件。有些报告需要修改一些文字,或者只是照本宣科 该文件必须保持为单个文本文件,因此要在文件中移动,比较行。如果发现一行是“ReportType1”,那么我们需要更改一些措辞,因此我们进入一个内部循环,提取数据并在执行过程中更改单词。循环在到达报表中的页脚时结束,并应转到下一个报表 我们尝试过-match,-like,-contains,-eq,但它从来没有像预期的那样工作。我们要么获取已更改/重新格式化但不应更改的数据,要么仅获取标题数据 Add-Ty

我们正在使用一个包含许多不同类型报告的文本文件。有些报告需要修改一些文字,或者只是照本宣科

该文件必须保持为单个文本文件,因此要在文件中移动,比较行。如果发现一行是“ReportType1”,那么我们需要更改一些措辞,因此我们进入一个内部循环,提取数据并在执行过程中更改单词。循环在到达报表中的页脚时结束,并应转到下一个报表

我们尝试过-match,-like,-contains,-eq,但它从来没有像预期的那样工作。我们要么获取已更改/重新格式化但不应更改的数据,要么仅获取标题数据

Add-Type -AssemblyName System.Collections
Add-Type -AssemblyName System.Text.RegularExpressions

[System.Collections.Generic.List[string]]$content = @()

$inputFile   = "drive\folder\inputfile.txt"
$outputFile  = "drive\folder\outputfile.txt"

#This will retrieve the total number of lines in the file
$FileContent = Get-Content $inputFile
$FileLineCount = $FileContent | Measure-Object -Line
$TotalLines = $FileContent.Count

$TotalLines++ #Need to increase by one; the last line is blank

$startLine   = 0
$lineCounter = 0

#Start reading the file; this is the Header section
#Number of lines may vary, but data is copied over word
#for word
foreach($line in Get-Content $inputfile)
{
    $startLine++
    If($line -match "FOOTER")
    {
        [void]$content.Add( $line )
        break
    }
    else
    {
        [void]$content.Add( $line )
    }
}
## ^^This section works perfectly

#Start reading the body of the file
Do {
    #Start reading from the current position
    #This should change with each report read
    $line = Get-Content $inputFile | select -Skip $startLine

    If($line -match "ReportType1") #If it's a ReportType1, some wording needs to be changed
    {
        #Start reading the file from the current position
        #Should loop through this record only
        foreach($line in Get-Content $inputFile | select -skip $startline) 
        {
            If($line -match "FOOTER") #End of the current record
            {
                [void]$content.Add( $line )
                break #break out of the loop and continue reading the file from the new current position
            }
            elseif ($line -match "OldWord") #Have to replace a word on some lines
            {
                $line = $line.Replace("OldWord","NewWord")
                [void]$content.Add( $line ) 
            }
            else
            { 
                [void]$content.Add( $line ) 
            }
            $startline++                
        }
    }
    else
    {
         If($line -match "ReportType2") #ReportType2 can just be copied over line for line
         {
             #Start reading the file from the current position
             #Should loop through this record only
             foreach($line in Get-Content $inputFile | select -skip $startline) 
             {
                If($line -match "FOOTER") #End of the current record
                {
                    [void]$content.Add( $line )
                    break #break out of the loop and continue reading the file from the new current position
                }
                else
                { 
                    [void]$content.Add( $line ) 
                }
                $startline++                
        }
    }
    $startline++
} until ($startline -eq $TotalLines)

[System.IO.File]::WriteAllLines( $outputFile, $content ) | Out-Null
这有点效果,但我们得到了一些意想不到的行为。这些报告看起来很好,但是它改变了“ReportType2”中的单词,即使代码没有设置为这样做。就好像它只通过了第一个IF语句。但是如果线不匹配怎么可能呢

我们知道$startline变量在迭代过程中不断增加,所以它不是停留在一行上。然而,执行“Write Host”显示$line始终是“ReportType1”,这不可能是真的,因为这些行在报告中的显示方式与预期的一致

样本数据:

<header data>
.
43 lines (although this can vary)
.
<footer>
<ReportType1> 
. 
x number of lines (varies)
. 
<footer> 
<ReportType2> 
. 
x number of lines (varies)
. 
<footer>

.
43行(尽管这可能有所不同)
.
. 
x行数(变化)
. 
. 
x行数(变化)
. 
以此类推,直到文件结束。不同类型的报告都混合在一起

我们所能想到的是,我们缺少了一些东西,可能是非常明显的,可以让它正确地输出数据


非常感谢您的帮助。

以下内容应为您提供所需的帮助。只需将
$oldword
$newword
的值替换为word替换项(目前不区分大小写),将
$report
的值替换为要更新的报告标题即可

$oldword = "Liability"
$newword = "Asset"
$report = "ReportType1"
$data = Get-Content Input.txt
$reports = $data | Select-String -Pattern $Report -AllMatches
$footers = $data | Select-String -Pattern "FOOTER" -AllMatches
$startindex = 0
[collections.arraylist]$output = foreach ($line in $reports) {
    $section = ($line.linenumber-1),($footers.linenumber.where({$_ -gt $line.linenumber},'First')[0]-1)
    if ($startindex -lt $section[0]-1) {
        $data[$startindex..($section[0]-1)]
    }
    if ($startindex -eq $section[0]-1) {
        $data[$startindex]
    }
    $data[$section[0]..$section[1]] -replace $oldword,$newword
    $startindex = $section[1]+1
}
if ($startindex -eq $data.count-1) {
    [void]$output.Add($data[$startindex])
}
if ($startindex -lt $data.count-1) {
    [void]$output.Add($data[$startindex..($data.count-1)])
}
$output | Set-Content Output.txt
代码说明:

$oldword
的目的是在正则表达式替换操作中使用。因此,任何特殊的正则表达式字符都需要转义。我选择在这里为你做这件事。如果要更新要替换的字符串,只需更新引号之间的字符。当我们将其传递给
-replace
操作符时,它不区分大小写

$newword
只是将替换
$oldword
输出的字符串。它不需要任何特殊处理,除非字符串包含特殊的PowerShell字符。替换文本将按原样显示,包括案例

$report
是要替换数据的节头的名称。当我们将其传递给
Select String-Pattern
时,它不区分大小写

$data
只是作为数组的文件内容。文件的每一行都是数组中的索引项

第一个
选择字符串
进行正则表达式匹配,正则表达式模式为
-pattern$Report
。它使用regex的原因是我们没有指定
-SimpleMatch
参数
-添加AllMatches
以捕获文件中
$Report
的每个实例。输出存储在
$Reports
中$报告是一个
MatchInfo
对象数组,这些对象具有我们将使用的属性,如
Line
LineNumber

第二个
选择字符串
进行正则表达式匹配,正则表达式模式为
-pattern“FOOTER”
。如果可能的话,你可以把它变成一个变量。它使用regex的原因是我们没有指定
-SimpleMatch
参数<代码>-添加所有匹配项,以捕获文件中
页脚
的每个实例

$startIndex
用于跟踪我们在阵列中的位置。它在帮助我们抓取所选文本的不同部分方面发挥了作用

$output
是一个数组列表,其中包含我们正在从
$data
读取的行以及与报告标题匹配的选定文本(选择字符串-模式$report输出)。它是一个arraylist,因此我们可以访问
Add()
方法来更有效地构建集合。它比使用
+=
和自定义对象数组更有效

代码的核心以一个
foreach
循环开始,该循环通过
$Reports
中的每个对象。每个当前对象都存储在
$line
中<代码>$Line将因此成为
MatchInfo
对象
$section
是一个行号数组(偏移-1,因为索引从0开始),它包含下一个
$report
匹配,通过下一个可用的
页脚
匹配。循环中的
if
语句只处理某些条件,例如
$report
是否匹配文件的第一行或第二行或下一节的第一行或第二行。
foreach
循环最终将输出第一个
$report
匹配之前的所有文本,每个
$report
匹配中的文本,包括
页脚
匹配,以及所有匹配之间的文本

foreach
循环之后的
if
语句将文件最后一次匹配之后的剩余部分添加到
$output

初始尝试的问题:

在您的尝试中,给您带来问题的是文件中报告的顺序。如果文件中ReportType1显示在ReportType2之后,则第一条
If
语句将始终为true。您没有检查一个行块。而是从某一行开始检查所有剩余的行。我会尽力的
1. <footer>
2. <ReportType2>
3. data
4. data
5. <footer>
6. <ReportType1>
7. data
8. <footer>