Powershell匹配数组时使用通配符

时间:2016-12-12 18:28:41

标签: arrays regex powershell wildcard

我现在已经把头撞到墙上好几个小时了,我正在寻求帮助。为了简化我的问题,我有两个数组,一个包含通配符,另一个使用这些通配符:

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

我无法让PowerShell认识到这些匹配。

我的最终目标是输出一个告诉我,Purple.102和orange.abc不在$ WildCardArray中。

似乎超级简单!我尝试过的一些事情:

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")
foreach($Item in $SpelledOutArray)
{
$item | where {$wildcardarray -contains $item}
}

我得到BLUE!.txt,因为它是我的控制,没有通配符。如果我将其更改为-notcontains,我将返回除BLUE之外的所有结果。我尝试过包含,匹配,等于,喜欢和所有对立面,比较对象,没有任何作品。我没有错误,我只是没有得到预期的结果

我尝试更换" *"使用[a-zA-Z]和其他组合,但它从字面上取代它,而不是作为通配符。我不确定我做错了什么...... PSVersion 5.1 Win 10

有没有人知道为什么/匹配/包含不起作用的背后的逻辑,以及我能做些什么让它起作用?它不一定非常漂亮,只需要工作

3 个答案:

答案 0 :(得分:3)

您的通配符数组实际上是要查找的模式列表。您可以将其转换为单个正则表达式并与之匹配:

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

# Turn wildcards into regexes
# First escape all characters that might cause trouble in regexes (leaving out those we care about)
$escaped = $WildcardArray -replace '[ #$()+.[\\^{]','\$&' # list taken from Regex.Escape
# replace wildcards with their regex equivalents
$regexes = $escaped -replace '\*','.*' -replace '\?','.'
# combine them into one regex
$singleRegex = ($regexes | %{ '^' + $_ + '$' }) -join '|'

# match against that regex
$SpelledOutArray -notmatch $singleRegex

虽然我没有测试,但它有可能比检查循环中的所有内容更快。此外,非常长的正则表达式也可能会带来麻烦。

答案 1 :(得分:2)

  

将我的头撞在墙上好几个小时[...]似乎超级简单!

这可能暗示它并非超级简单。你试图交叉匹配两个列表:红色到红色,黄色,蓝色......然后蓝色到红色,黄色,蓝色......然后绿色到红色,黄色,蓝色...... 。 30次比较,但你只发生了5次循环。

你需要更多。

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

# Loop once over the spelled out items
foreach($Item in $SpelledOutArray)
{
    # for each one, loop over the entire WildCard array and check for matches
    $WildCardMatches = foreach ($WildCard in $WildCardArray)
    { 
        if ($item -like $WildCard) {
            $Item
        }
    }

    # Now see if there were any wildcard matches for this SpelledOut Item or not
    if (-not $WildCardMatches)
    {
        $Item 
    }
}

并且WildCardArray上的内部循环可以成为过滤器,但您必须过滤数组,而不是像代码那样过滤单个项目。

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

foreach($Item in $SpelledOutArray)
{
   $WildCardMatches = $wildcardarray | Where { $item -like $_ }

   if (-not $WildCardMatches)
   {
       $Item 
   }
}

我猜你可以把它混合成一个不清楚的双重过滤器,如果你不得不这样做。

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

$SpelledOutArray |Where {$item=$_; -not ($WildCardArray |Where {$item -like $_}) }

答案 2 :(得分:1)

$WildCardArray = @("RED-*.htm", "*.yellow", "BLUE!.txt", "*.green", "*.purple")
$SpelledOutArray = @("RED-123.htm", "456.yellow", "BLUE!.txt",  "789.green", "purple.102", "orange.abc")

$WildCardArray | %{$str=$_; $SpelledOutArray | ? {$_ -like $str}  }

其他解决方案,而不是短暂的

$WildCardArray | 
   %{$current=$_; $SpelledOutArray | %{ [pscustomobject]@{wildcard=$current; value=$_ }}} | 
        where {$_.value -like $_.wildcard }