使用下一个匹配作为分隔符匹配字符串

Matching Strings Using Next Match as Delimiter

当通过正则表达式匹配粗略的文本文件时,我想匹配匹配之间的字符串,包括匹配;在将这些写入文件之前。由于文本的随机性,我无法使用句号或换行符来分隔匹配项。但是我可以写出字符串的匹配部分。但我想要整个字符串。

示例文本文件包含混乱的条目

# this text file replicates a jumbled double listing
001 AALTON, Alan .....25 Every Street006 JOHNS, Jason .... 3 Steep Street 002 BROWN,
James .... 101 Browns Road
005 INSTONE, June .... 14 Dover Road 003 BROWN, Jemmima ........ 101 Browns Road 004 BROWN, John ....... 
101 Browns Road 
005 CAMPBELL, Colin ..... 57 Camp Avenue
004 HANNAH, Harold ....7 Right Way
006 DONNAGAN, Dolores ...11 Main Road
001 EMERSON, John .... 13 South Street
002 FLANAGAN, Lesley .... 1 Lovers Lane
003 GREGG, Ian ..... 101 Short Street

正在使用

$regexRen = '\d\d\d\s[A-Z][A-Z][A-Z]'
$result = select-string -AllMatches -Path $input_path -Pattern $regexRen -CaseSensitive | % { $_.Matches } | % { $_.Value }

我可以用这种输出按字母顺序输出以下内容:

001 AAL
002 BRO
003 BRO
004 BRO
005 CAM
006 DON
001 EME
002 FLA
003 GRE

我想要的是直到下一场比赛的整个字符串。而且,我想,这也会处理多个 BROWN 名称。那是 return 布朗人名的正确字母顺序。

如有任何建议,我们将不胜感激。

注:

  • 更简单更快。

  • 下面的解决方案可能仍然对以下技术感兴趣:

    • 使用 -split 拆分 multi-line 字符串,通过正则表达式捕获组 ((...))
    • 使用Group-Object成对处理数组。

我建议使用 -split operator, combined with Group-Object and Sort-Object:

$i = @{ Index = 0 }
(Get-Content -Raw $input_path) -csplit '(\d{3}\s[A-Z]{3})' -ne '' | 
  Group-Object { [math]::Floor($i.Index++ / 2) } |
    ForEach-Object { (-join ($_.Group -replace '\r?\n', ' ')).TrimEnd() } |
      Sort-Object { (-split $_)[1] }

输出样本输入(每个输出字符串包含在 «...» 中以说明各个结果字符串):

«001·AALTON,·Alan·.....25·Every·Street»
«002·BROWN,·James·....·101·Browns·Road»
«003·BROWN,·Jemmima·........·101·Browns·Road·»
«004·BROWN,·John·.......··101·Browns·Road··»
«005·CAMPBELL,·Colin·.....·57·Camp·Avenue·»
«006·DONNAGAN,·Dolores·...11·Main·Road·»
«001·EMERSON,·John·....·13·South·Street·»
«002·FLANAGAN,·Lesley·....·1·Lovers·Lane·»
«003·GREGG,·Ian·.....·101·Short·Street·»
«004·HANNAH,·Harold·....7·Right·Way·»
«005·INSTONE,·June·....·14·Dover·Road·»
«006·JOHNS,·Jason·....·3·Steep·Street·»

注意:如果输入行有 前导空格,则需要做更多的工作。

$i = @{ Index = 0 }
(Get-Content $input_path).TrimStart() -join "`n" -csplit '(\d{3}\s[A-Z]{3})' -ne '' | 
  Group-Object { [math]::Floor($i.Index++ / 2) } |
    ForEach-Object { (-join ($_.Group -replace '\r?\n', ' ')).TrimEnd() } |
      Sort-Object { (-split $_)[1] }

使用 Wiktor 漂亮的正则表达式你可以做这样的事情

$regexRen = '(?s)(?<!\d)\d{3}\s[A-Z]{3}.*?\D(?=\d{3}\s[A-Z]{3}|$)'
Select-String -AllMatches -Path $input_path -Pattern $regexRen -CaseSensitive | 
    ForEach-Object { $_.Matches.Value -replace '[\n\r]' } | 
        Sort-Object { $_.substring(4, 5) }

输出

001 AALTON, Alan .....25 Every Street
002 BROWN,James .... 101 Browns Road
003 BROWN, Jemmima ........ 101 Browns Road
004 BROWN, John .......101 Browns Road
005 CAMPBELL, Colin ..... 57 Camp Avenue
006 DONNAGAN, Dolores ...11 Main Road
001 EMERSON, John .... 13 South Street
002 FLANAGAN, Lesley .... 1 Lovers Lane
003 GREGG, Ian ..... 101 Short Street
004 HANNAH, Harold ....7 Right Way
005 INSTONE, June .... 14 Dover Road
006 JOHNS, Jason .... 3 Steep Street