Regex Powershell正则表达式-捕获“;“太多”;(不遵守非贪婪指标?)

Regex Powershell正则表达式-捕获“;“太多”;(不遵守非贪婪指标?),regex,xml,powershell,Regex,Xml,Powershell,下面的代码正在返回: partner=<Partner> more stuff <Name>Test</Name> other things </Partner> <Partner> more stuff <Name>CompanyX</Name> other things </Partner> 合作伙伴= 更多材料测试 其他事情 更多材料公司 其他事情 但我希望它能回来: partn

下面的代码正在返回:

partner=<Partner>
 more stuff <Name>Test</Name>
 other things </Partner>  <Partner>
 more stuff <Name>CompanyX</Name>
 other things </Partner> 
合作伙伴=
更多材料测试
其他事情
更多材料公司
其他事情
但我希望它能回来:

partner=<Partner>
 more stuff <Name>CompanyX</Name>
 other things </Partner> 
合作伙伴=
更多材料公司
其他事情
示例代码:

$partyName = "CompanyX" 

#$bindings = [IO.File]::ReadAllText($inputFileName)

$bindings = "starting stuff <Partner>`r`n more stuff <Name>Test</Name>`n other things </Partner>  <Partner>`r`n more stuff <Name>CompanyX</Name>`n other things </Partner> ending stuff" 


$found = $bindings -match "(?s)(<Partner>.*?<Name>$partyName</Name>.*?</Partner>)"

if ($found) 
{
    Write-Host "matched"
    $partner = $matches[1]
}

Write-Host "partner=$partner "
$partyName=“CompanyX”
#$bindings=[IO.File]::ReadAllText($inputFileName)
$bindings=“开始资料`r`n更多资料测试`n其他资料`r`n更多资料公司`n其他资料结束资料”
$found=$bindings-match“(?s)(*?$partyName.*?”
如有($已找到)
{
写入主机“匹配”
$partner=$matches[1]
}
写入主机“partner=$partner”

正如InCorrigible1所说:使用xml解析器而不是正则表达式

然而。。由于使用正则表达式进行此操作的原因可能只是为了查看是否可以使用正则表达式以及如何使用正则表达式进行此操作,您可以使用:

$found = $bindings -match "(?sx)(<Partner>(?:((?!</Partner>).)+<Name>$([Regex]::Escape($partyName))</Name>)(?:((?!</Partner>).))*</Partner>)"
$found=$bindings-match“(?:(?!)+$([Regex]::Escape($partyName))(?:(?!))*”

非贪婪复制符号(
*?
)正在得到尊重,但在这种情况下,它们还不够:

*?$partyName
元素的下一个实例之间匹配,但这并不保证中间不会有另一个
标记。
换句话说:您的正则表达式将始终在第一个
标记和感兴趣的
元素之间匹配

为了防止出现这种情况,您需要一个否定(
(?!…)
)来排除插入的
标记:

# Sample input, defined as a here-string.
$bindings = @'
starting stuff <Partner>
more stuff <Name>Test</Name>
 other things </Partner> <Partner>
 stuff of interest before <Name>CompanyX</Name>
 stuff of interest after </Partner> even more </Partner> ending stuff
'@ 

# Escape the name to ensure it is treated as a literal inside the regex.
# Note: Not strictly necessary for sample value 'CompanyX'
$partyName = [regex]::Escape('CompanyX')

# Use a negative look-ahead assertion - (?!...) - to rule out intervening
# <Partner> tags before the <Name> element of interest.
if ($bindings -match "(?s)<Partner>((?!<Partner>).)*<Name>$partyName</Name>.*?</Partner>") {
  # Output the match.
  $matches[0]
} else { 
  Write-Warning 'No match.'
}
#示例输入,定义为here字符串。
$bindings=@'
起始材料
更多材料测试
其他事情
在CompanyX之前感兴趣的东西
在更多的结尾之后的有趣的东西
'@ 
#转义名称以确保它在正则表达式中被视为文本。
#注:对于样本值“CompanyX”而言,不完全是必需的
$partyName=[regex]::转义('CompanyX')
#使用否定的前瞻性断言(?!…)来排除干预
#在感兴趣的元素之前添加标记。
if($bindings-match“(?!)((?!))*$partyName.*?){
#输出匹配项。
$matches[0]
}否则{
写下警告“不匹配”
}
上述收益率:

<Partner>
 stuff of interest before <Name>CompanyX</Name>
 stuff of interest after </Partner>

在CompanyX之前感兴趣的东西
后感兴趣的东西
  • (?!)。
    匹配一个字符(
    ),前面没有字符串

  • 此子表达式本身必须与开头
    和感兴趣的
    元素之间的每个字符(如果有)匹配,因此它被包装在
    (…)*

    • 我认为这会导致效率低下的匹配算法,但它确实有效。
      如前所述,在XPath查询中使用适当的XML解析是值得考虑的替代方法

    • 您可以使用
      (?:…)*
      作为包装器,告诉正则表达式引擎不要捕获子表达式的(最新)匹配,从而提高匹配效率。(
      (…)
      是捕获组,这意味着子表达式匹配的内容将作为自动变量
      $matches
      返回的内容的一部分进行报告,这在这里是不需要的,因此
      ?:
      将禁止该操作)


可能的重复简而言之:不要自己用正则表达式解析XML。。。使用xml解析器。删除我的答案,因为它太脆弱了。我相对确信,非常熟悉平衡结构的人可以给你一个合理的正则表达式…但我怀疑即使这样,手动解析解决方案也会更容易让大多数人阅读。概括来说,基本问题是,一旦正则表达式引擎看到它的第一个
,它开始工作,使匹配。通过这场比赛,它尽可能地尊重懒惰指标。换句话说,它基本上是从左到右工作的。