如何在两个单词之间提取多个字符串

时间:2019-10-23 16:13:12

标签: regex string powershell find

我正在使用Powershell来获取日志文件的内容。我试图提取两个已知单词之间的未知字符串。我需要对多行执行此操作,因此我想搜索并返回多个字符串。我看过很多例子,并尝试了不同的方法,但是它们没有用。

我已经使用reg ex将其范围缩小到我关心的日志中的行,但是我无法提取所需的文本。

$fails =  Select-String -Path 'C:\Users\user\Documents\wsyncmgr.log'  -Pattern "^(?=.*?\bError\b)(?=.*?\bSoftware\b)(?=.*?\bLicense\b)(?=.*?\bTerms\b)(?=.*?\bnot\b)(?=.*?\bdownloaded\b).*$"

这将返回:

C:\Users\user\Documents\wsyncmgr.log:7340:Failed to sync update 817ad2a6-3ca7-4fa2-aa32-9b906a2d9fdc. Error: The Microsoft Software License Terms have not been completely 
downloaded and~~cannot be accepted. Source: Microsoft.UpdateServices.Internal.BaseApi.SoapExceptionProcessor.DeserializeAndThrow  $$<SMS_WSUS_SYNC_MANAGER><10-23-2019 
08:31:07.642+300><thread=5916 (0x171C)>
C:\Users\user\Documents\wsyncmgr.log:7341:Failed to sync update 87e13ecb-c669-43be-9e2a-01e567285031. Error: The Microsoft Software License Terms have not been completely 
downloaded and~~cannot be accepted. Source: Microsoft.UpdateServices.Internal.BaseApi.SoapExceptionProcessor.DeserializeAndThrow  $$<SMS_WSUS_SYNC_MANAGER><10-23-2019
08:31:07.643+300><thread=5916 (0x171C)>

等等。

我只想提取更新的唯一ID,这样我就可以将它们全部放入变量中,以后再使用。

我最近的是 $removeFirst = $fails -split "update "  $removeLast = $removeFirst -split ". Error:"  $removeLast[1]

C:\Users\user\Documents\wsyncmgr.log:7341:Failed to sync 
87e13ecb-c669-43be-9e2a-01e567285031
 The Microsoft Software License Terms have not been completely downloaded and~~cannot be accepted. Source: Microsoft.UpdateServices.Internal.BaseApi.SoapExceptionProcessor.DeserializeAndThrow  $$<SMS_WSUS_SYNC_MANAGER><10-23-2019 08:31:07.643+300><thread=5916 (0x171C)>
C:\Users\user\Documents\wsyncmgr.log:7342:Failed to sync
c1a1ec21-8efc-4cd4-8e85-90a03fc7b0c8
 The Microsoft Software License Terms have not been completely downloaded and~~cannot be accepted. Source: Microsoft.UpdateServices.Internal.BaseApi.SoapExceptionProcessor.DeserializeAndThrow  $$<SMS_WSUS_SYNC_MANAGER><10-23-2019 08:31:07.644+300><thread=5916 (0x171C)>
C:\Users\user\Documents\wsyncmgr.log:7343:Failed to sync
09dc7113-fa44-4ca8-9d70-ec254d4d2f04
 The Microsoft Software License Terms have not been completely downloaded and~~cannot be accepted. Source: Microsoft.UpdateServices.Internal.BaseApi.SoapExceptionProcessor.DeserializeAndThrow  $$<SMS_WSUS_SYNC_MANAGER><10-23-2019 08:31:07.644+300><thread=5916 (0x171C)>

但这只会删除我指定的单词,并将其余的放在单独的行上。然后数组只返回我指定的行,但我要多个。我想消除“更新”之前的所有内容以及“。错误之后”的所有内容。 每行只保留“ 09dc7113-fa44-4ca8-9d70-ec254d4d2f04”。

使用正则表达式不好对任何帮助表示赞赏

2 个答案:

答案 0 :(得分:1)

如果您的ID具有相同的结构,则可以执行以下操作:

$fails | Select-String '(?:[a-z0-9]+-){4}[a-z0-9]+' |
  ForEach-Object { $_.Matches.Value }

说明:

  • (?:[a-z0-9]+-)非捕获组,匹配一个或多个字母数字字符,并以-结尾
  • {4}匹配四次
  • [a-z0-9]+匹配一个或多个字母数字字符。

由于将捕获多行,因此每条匹配的行将是一个MatchInfo对象。通过插入Foreach-Object,我们可以像$_一样访问每个对象。 .Matches.Value将仅检索该对象的匹配值。

答案 1 :(得分:0)

在字符串上使用[regex]::matches方法(必须提供正则表达式进行匹配),然后检查返回的数组以查找字符串中的每个特定匹配项。这是一个示例:

$myString = "The quick brown fox"
$myMatches = [regex]::matches($myString, "\w+")
$myMatches.Value

上面的示例在字符串中查找单词。 matches方法匹配多次,而-match运算符没有全局匹配选项(我发现,很可能会在这里被证明是错误的)。 .Value属性包含实际匹配项,尽管您也可以在System.Text.RegularExpressions.Match对象上使用其他有用的成员。

编辑

您的问题有点模棱两可:

  • 我正在尝试提取两个已知单词之间的未知字符串。
  • 我只想提取更新的唯一ID

我错过了第二部分,所以让我在这里解决。由于您要从字符串中选择已知模式(唯一ID),因此您可以 使用-match运算符:

$fails | Foreach-Object {
  if( $_ -match '[a-z0-9]{8}-([a-z0-9]{4}-){3}[a-z0-9]{12}') ){
    $matches[0]
}

$matches是一个特殊的数组,当使用-match运算符进行匹配时,该匹配项将放入$matches的0索引中。过去的每个指示捕获组匹配的索引,但是您在这里不需要。

我提供的表达式是针对格式正确的UUID的,应与MS regex引擎以及PCRE和Javascript一起使用。当然,请确保使用不区分大小写的匹配,或者在其他情况下根据需要添加大写字母变体。