2016-12-12 3 views
0

Я уже несколько часов стуча головой о стену и ищу какую-то помощь. Чтобы упростить мой вопрос, у меня есть два массива, один из которых содержит символы, а другой, который использует эти символы:Powershell Используйте подстановочные знаки при сопоставлении массивов

$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} 
} 

я СИНИЙ .txt в результате, потому что это мой контроль, без масок!. Если я изменю это на -notcontains, я получаю все полученные результаты, кроме BLUE. Я пробовал содержать, сопоставлять, равно, как и все их противоположности, сравнивать-объект, и ничего не работает. Я не получаю ошибок, я просто не получаю ожидаемых результатов.

Я попытался заменить «*» на [a-zA-Z] и другие комбинации, но он заменяет его буквально, а не как подстановочный знак. Я не уверен, что я делаю неправильно .... PSVersion 5.1 Win 10

Кто-нибудь знает логику ПОЧЕМУ, как/match/contains не работает, и что я могу сделать, чтобы он работал? Он не должен быть очень, он просто должен работать

+1

'-contains' ищет точное соответствие, и я уверен, что это угрозы' * 'как символ без какого-либо особого значения. – 4c74356b41

+0

' $ WildCardArray | ForEach-Object {$ Wildcard = $ _; $ SpelledOutArray | Where-Object {$ _ -like $ WildCard}} ' – beatcracker

+0

@beatcracker, который дает неверный результат. – TessellatingHeckler

ответ

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 $_}) } 
+0

Это прекрасно работает, спасибо! Знаете ли вы, как ваше решение держится под большим объемом данных? Если, например, $ WildCardArray должен содержать 1000 элементов, а $ SpelledOutArray - более 100 тыс.? – Nick

+0

@Nick Это будет работать, но, вероятно, медленно, это O (N * M). Возможно, вам будет лучше, если вы сможете объединить все свои подстановочные знаки в одно регулярное выражение, например. '@ (« RED-123.htm »,« 456.yellow »,« BLUE! .txt »,« 789.green »,« purple.102 »,« orange.abc ») -notmatch '^ RED -. * \ .htm |. * \. yellow | BLUE! \. txt |. * \. green |. * \. purple $ ''делает это для вашего примера. Но вы сказали, что ваш пример упрощен, так что это может быть нелегко/возможно для всего, что вы действительно делаете. – TessellatingHeckler

+0

@TessellatingHeckler: Забавно, что вы должны упомянуть об этом; это то, с чем я пошел в своем ответе ;-) – Joey

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 } 
+0

Это дает неверный результат ... »* Моя конечная цель - получить вывод, который говорит мне, что purple.102 и orange.abc не находятся в $ WildCardArray. *", Но ваш код выводит 'RED - *. Htm *. желтый ГОЛУБОЙ! .txt * .green' – TessellatingHeckler

+0

ты прав, я изменил свой ответ – Esperento57

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 

Это имеет потенциал, чтобы быть быстрее, чем проверять все в цикле, хотя я не проверял. Кроме того, необычно длинные регулярные выражения могут также вызвать проблемы.

+0

I ' вы не знаете, что это такое, и у вас есть вопрос. Кажется, это буквально означает «.», что означает, что подстановочный знак * .yellow будет тянуть «123.greenyellow». Является ли это причудой регулярного выражения? Я искал подстановочные знаки, но, похоже, не мог понять это. – Nick

+0

@Nick: Извините, моя экранирующая замена фактически _removed_ все эти символы вместо того, чтобы ускользнуть от них. Я исправил это сейчас. – Joey