我要打印单词存在于文本文件中并打印“匹配”和“不匹配”。我的第一个文本文件是:xxaavv6J
,我的第二个文件是6J6SCa.yB
。
如果匹配,则返回如下:
Match found: Match found: Match found: Match found: Match found: Match found: 6J Match found: Match found: Match found:
我的期望只是打印match
和not match
。
$X = Get-Content "C:\Users\2.txt"
$Data = Get-Content "C:\Users\d.txt"
$Split = $Data -split '(..)'
$Y = $X.Substring(0, 6)
$Z = $Y -split '(..)'
foreach ($i in $Z) {
foreach ($j in $Split) {
if ($i -like $j) {
Write-Host ("Match found: {0}" -f $i, $j)
}
}
}
答案 0 :(得分:2)
操作-split '(..)'
不会产生您认为会产生的结果。如果查看以下命令的输出,您会看到很多空结果:
PS C:\> 'xxaavv6J' -split '(..)' | % { "-$_-" } -- -xx- -- -aa- -- -vv- -- -6J- --
这些空值是您从$i -like $j
获得的其他匹配项。
我不太确定为什么-split '(..)'
会首先为您提供任何非空值,因为我希望它会为输入字符串“ xxaavv6J”生成5个空字符串。显然,它与分组括号有关,因为-split '..'
(不带分组括号)实际上的行为确实符合预期。看起来与捕获组一样,捕获的匹配项将返回到拆分操作结果的顶部。
无论如何,要获得想要替换的行为
... -split '(..)'
使用
... |
Select-String '..' -AllMatches |
Select-Object -Expand Matches |
Select-Object -Expand Value
您还可以将嵌套循环替换为以下内容:
foreach ($i in $Z) {
if (if $Split -contains $i) {
Write-Host "Match found: ${i}"
}
}
答案 1 :(得分:0)
使用正则表达式'.Match()'的方法稍有不同,也应该这样做。
我为您添加了很多解释性注释:
$Test = Get-Content "C:\Users\2.txt" -Raw # Read as single string. Contains "xxaavv6J"
$Data = (Get-Content "C:\Users\d.txt") -join '' # Read as array and join the lines with an empty string.
# This will remove Newlines. Contains "6J6SCa.yB"
# Split the data and make sure every substring has two characters
# In each substring, the regex special characters need to be Escaped.
# When this is done, we join the substrings together using the pipe symbol.
$Data = ($Data -split '(.{2})' | # split on every two characters
Where-Object { $_.Length -eq 2 } | # don't care about any left over character
ForEach-Object { [Regex]::Escape($_) } ) -join '|' # join with the '|' which is an OR in regular expression
# $Data is now a string to use with regular expression: "6J|6S|Ca|\.y"
# Using '.Match()' works Case-Sensitive. To have it compare Case-Insensitive, we do this:
$Data = '(?i)' + $Data
# See if we can find one or more matches
$regex = [regex]$Data
$match = $regex.Match($Test)
# If we have found at least one match:
if ($match.Groups.Count) {
while ($match.Success) {
# matched text: $match.Value
# match start: $match.Index
# match length: $match.Length
Write-Host ("Match found: {0}" -f $match.Value)
$match = $match.NextMatch()
}
}
else {
Write-Host "Not Found"
}
结果:
Match found: 6J
答案 2 :(得分:0)
进一步到excellent Ansgar Wiechers' answer:如果您正在运行Windows上的 Windows PowerShell 4.0 ,则可以应用 Kirk Munro .Where()方法>的详尽文章ForEach and Where magic methods:
随着Windows PowerShell 4.0的发布,两个新的“魔术”方法 引入了为提供新语法的集合类型 访问Windows PowerShell中的
ForEach
和Where
功能。 这些方法恰当地命名为ForEach
和Where
。我打电话 这些方法“神奇”,因为它们在工作方式上非常神奇 在PowerShell中。它们不会显示在Get-Member
输出中,即使您 申请-Force
并请求-MemberType All
。 如果您汇总 袖子,用反射挖出来,你可以找到它们;但是,它 需要广泛的搜索,因为它们是私有扩展方法 在私有类上实现。即使他们不是 可被发现而无需在底下偷看,当您 需要它们,它们比同龄人更快,而且 包括较老版本不可用的功能 同行,因此当您 在PowerShell中使用它们。不幸的是,这些方法仍然存在 直到今天,也就是自公开发布以来,已经有将近一年的时间了 发布,所以很多人没有意识到 这些方法。
…Where方法
Where
是一种允许您过滤对象集合的方法。 这非常类似于Where-Object
cmdlet,但是Where
方法也类似于Select-Object
和Group-Object
, 包含Where-Object
cmdlet的其他一些功能 本身并没有本地支持。此方法提供了更快的速度 比简单Where-Object
的命令更优雅。喜欢ForEach
方法,此方法输出的任何对象都是 返回类型的通用集合System.Collections.ObjectModel.Collection1[psobject]
。此方法只有一个版本,可以描述为 如下:
Where(scriptblock expression[, WhereOperatorSelectionMode mode[, int numberToReturn]])
如方括号所示,
expression
脚本块为 必需和mode
枚举以及numberToReturn
整数 参数是可选的,因此您可以使用1、2或3调用此方法 论点。如果要使用特定参数,则必须提供 该参数左侧的所有参数(即,如果您想 为numberToReturn
提供一个值,您必须为mode
和expression
。
适用于您的情况(使用Where(scriptblock expression)
方法的最简单的变体.Where()
):
$X = '6J6SCa.yB' # Get-Content "C:\Users\2.txt"
$Data = 'xxaavv6J' # Get-Content "C:\Users\d.txt"
$Split = ($Data -split '(..)').Where({$_ -ne ''})
$Y = $X.Substring(0, 6)
$Z = ($Y -split '(..)').Where{$_ -ne ''} # without parentheses
例如,Ansgar的示例更改如下:
PS > ('xxaavv6J' -split '(..)').Where{$_ -ne ''} | % { "-$_-" }
-xx-
-aa-
-vv-
-6J-