首页 > 解决方案 > 用于将多行文本提取到单行的 Powershell 脚本

问题描述

我需要通过 powershell 从文本文件中提取一些文本行到基于某些标准的新输出文件中,然后还将下一行的一些数据提取到同一行中。

这是文本文件的示例:

0 CARDHOLDER NUMBER     TOKEN NUMBER          MESSAGE DATE/TIME    ACTIVITY REASON            NTWK   PAN EXP  TRAN ID                
0 1234567890123456      4234567890123456      11/12/14  15:34:38   T1-TKN CREATE              VSN     49/12   314316099993286        
     TOKEN DATA: EXP DATE: 16/05   REQUESTOR ID: 45432112345   TYPE: T0   STATUS: I   ASSURANCE LEVEL: 16   REQUEST METHOD: 6        
                 TOKEN REF ID: TOKENREFERENCEDATAID012345678901 PAN REF ID: PANREFERENCEID                                           
          TERMS: VERSION: Terms and condition verification data                           DATE/TIME: Mon, 07 Apr 2014 10:25:217      
   TEXT MESSAGE: $TM*TOKEN NOTIFICATION ADVICE                                                                                       
0 5678901234561234      4234567890123456      11/12/14  15:34:44   T2-TKN DEACTIVATE          VSN     49/12   314316100043288        
     TOKEN DATA: EXP DATE: 16/05   REQUESTOR ID: 45432112345   TYPE: T0   STATUS: I   ASSURANCE LEVEL: 16   REQUEST METHOD: 6        
                 TOKEN REF ID: TOKENREFERENCEDATAID012345678901 PAN REF ID: PANREFERENCEID                                           
          TERMS: VERSION: Terms and condition verification data                           DATE/TIME: Mon, 07 Apr 2014 10:25:217      
   TEXT MESSAGE: $TM*TOKEN NOTIFICATION ADVICE  

所需的输出会将持卡人编号和请求者 ID 放在一行中,例如:

1234567890123456,45432112345 
5678901234561234,45432112345

现在我有以下代码,但它不会从下一行提取子字符串,而是与卡号对齐:

$report = get-content $inputFile

foreach ($line in $report) { 
    if ($line -match 'T5-DEVICE PRV RSLT') {
        $card = $line.Substring(2,16)
        $lineRequestor = $line + 1
        $requestorID = $lineRequestor.SubString(49,11)
        if ($card.StartsWith("4")) {
            $card = $card + ','
            $output = $card + $requestorID
            $output | out-file -FilePath $outputFile -Append
        }
    }
}

标签: powershell

解决方案


以下基于简化Select-String的解决方案通过它们包含的位数(分别为16和)识别要提取的两条数据。11

# Search for lines with cardholder numbers and include one line below
# (-Context 0, 1)
Select-String '\b\d{16}\b' $inputFile -Context 0,1 | ForEach-Object { 
  # Match the requestor ID on the line below.
  $null = $_.Context.PostContext[0] -match '\b\d{11}\b';
  # Output the cardholder number found by Select-String and the
  # requestor ID found with -match
  $_.Matches[0].Value + ',' + $Matches[0] 
} # | Set-Content $outputFile 

删除#以保存到$outputFile

使用您的示例输入文件,这会产生:

1234567890123456,45432112345
5678901234561234,45432112345

至于你尝试了什么:

$lineRequestor = $line + 1

这不是获取下一个输入行,而是与当前行执行字符串连接并附'1'加到它。

通常,您不能(轻松)在foreach循环执行的枚举中向前跳过。[1]

如果您想这样做,请使用带有indicesfor的循环,如下面的简化示例所示:

$lines = 'one', 'two', 'three', 'four'
for ($i = 0; $i -lt $lines.Count; ++$i) {
  # Output a pair of lines.
  "item + next item: " + $lines[$i] + ', ' + $lines[++$i]
}

[1] 从技术上讲,你可以,但解决方案是模糊的,通过自动$foreach变量:
foreach ($line in 'one', 'two', 'three', 'four') { $null = $foreach.MoveNext(); $nextLine = $foreach.Current; "$line - $nextLine" }


推荐阅读