【问题标题】:powershell multiline regex blockpowershell 多行正则表达式块
【发布时间】:2016-10-24 18:15:21
【问题描述】:

在尝试使用多行正则表达式时,我真的很沮丧,我对 Powershell 的经验很少,虽然我尝试过的示例有效,但一旦我开始根据需要调整它们它永远不会给出任何结果。

下面是我的文本文件示例

CLO*5000000Z115240057*598.50***94>0
DGP*115*G8*20161024~
DGP*096*G8*20161024~
DI*ABC>121~
QM1*BN*1*~
QM2*H2*1*~
QM1397*2*~
Q3*~
Q4*~
TX*1~
SQU*HV>01480>AB>1S>1>2>3>4~
0T1*472*D8*20160915~
RBF*6R*374196~
TX*2~

在同一个文本文件中可能有 200 个(最多)这些。我正在寻找以“SQU”开头的行,最后包含 1>2>3>4,只有少数几个这样做。我可以使用下面找到的代码示例找到所有 SQU 行,不幸的是,我还需要获取位于其上方的“CLO”行。

$fpath = 'C:\myfile.txt'
$opath = 'C:\logoutput.txt'
$regx = 'SQU.*1>2>3>4.*'
Get-Content $fpath | % { if($_ -match $regx) {add-content $opath $_}}

我已经尝试过了,并且我已经尝试了几十个 $'s 和 ^'s 和 ()'s 在下面的示例中,在我能想到的每个组合中。我也不太明白如何将其放入 logoutput.txt。

$fileContent = [io.file]::ReadAllText($fpath)
$filecontent | Select-String '(?ms)CLO.*SQU.*1>2>3>4.*' -AllMatches | %{ $_.Matches } | %{ $_.Value } 

这个我试过没有 >1>2>3>4 只是想看看我能不能得到任何东西,但没有运气。

$stringmatch = Get-Content -raw $fpath
if (Select-String -inputobject $stringmatch -pattern '(?smi)CLO.*SQU.*'){
$matches[1]
} 

我只需要 CLO 和 SQU 行(如果它有 1>2>3>4),但老实说,在这一点上,如果更容易的话,我会占用整个块。 任何帮助将不胜感激。

【问题讨论】:

  • CLO 线是否总是距离 SQU 10 线?
  • 不,不是,其中一些行不在以 CLO 开头的每个块中,有时甚至还有其他行 - 它们确实在每个块中都有 CLO 和 SQU 行(希望有意义)

标签: regex powershell multiline


【解决方案1】:
$fileContent = [io.file]::ReadAllText($fpath)

# Match lines beginning with CLO, and lines beginning with SQU
$m = [regex]::Matches($fileContent,
                      '(?<clo>^CLO.*?$).*?(?<squ>^SQU.*?$)',
                      [System.Text.RegularExpressions.RegexOptions]('Multiline', 'Singleline')) 

# Filter out only the pairs where the SQU lines also have the right ending
$m | Where-Object { $_.Groups['squ'].Value -match "1>2>3>4~" } | 
     ForEach-Object { 
        $_.Groups['clo'].Value
        $_.Groups['squ'].Value
} 

【讨论】:

  • MatthewG :由于某种原因,从 powershell ISE 运行它时,它会永远挂起。谢谢你为我解释它
  • TessellatingHeckler :这对我有用,也感谢您的解释。感谢你们俩的帮助,也许我现在可以冷静下来了。
  • (?sm) 可用于设置单行+多行模式:quick reference
【解决方案2】:

在您的第二个示例中 - 您读取文本文件,然后匹配正则表达式,然后打印出值。该值将显示匹配的全部内容,其中包括 CLO 和 SQU 之间的所有 .*。而是在您关心的行上使用组捕获(使用括号),然后仅打印组的值。

另外 - 修改正则表达式以使用非贪婪匹配,因此多个匹配将正常工作。 对正则表达式的另一个修改是您不想匹配 CLO 和 SQU 组的行尾之后的字符 - 因此请确保这些匹配以行尾 $ 指示符结尾。

$fileContent = [io.file]::ReadAllText($fpath)
$filecontent | Select-String '(?ms)(CLO[^\n]*?$).*?(SQU.*?1>2>3>4[^\n]*$)' -AllMatches | %{ $_.Matches } | %{ $_.Groups[1].Value; $_.Groups[2].Value }

【讨论】:

  • 如果有一条 SQU 行不以 1&gt;2&gt;3&gt;4 结尾,那么您的 SQU.*?1&gt;2&gt;3&gt;4 匹配将跨越后续行,越过下一个 CLO 行,一直到下一个确实以这种方式结束的行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多