使用包含条件和通配符的数组时出现问题 [英] Issue using an array containing criteria with wildcards
问题描述
我一直在尝试运行powershell代码将文件拆分为2.
I've been trying to run a powershell code to split a file in 2.
我有几个常规数组,效果很好. 第三个数组包含每个条件的通配符,这根本不起作用.
I've got a couple of regular arrays, that works just fine. The 3rd array contains wildcards for each of the criteria, and that doesn't work at all.
我已经尝试-in -notin,-like -notlike,-contains -notcontains,-match -notmatch,但我没有得到想要的结果.
I've tried -in -notin, -like -notlike, -contains -notcontains, -match -notmatch, i'm not getting the results I want.
$NonAutoStructure = @("Not_Found", "UK Training Centre", "IRISH Training Centre", "Head Office", "UK Newmedica")
$AutoJournalDescriptions = @("STORE TRANFrom *", "*SALES BANKED*")#, "*/* CREDIT" , "BANKING DIFF*BQ*" , "*/* MASTERCARD/VISA")
$InactiveStores = @("4410", "0996", "1015", "5996")
$NonAutoJournalCompanies = {$_.Description -notcontains $AutoJournalDescriptions}
$AutoJournalCompanies = {$_.Description -contains $AutoJournalDescriptions}
#$NonAutoJournalCompanies = {$_.structure -in $NonAutoStructure -or $_.Company -in $InactiveStores -and $_.Amount -ne "0.00"}
#$AutoJournalCompanies = {$_.structure -notin $NonAutoStructure-and $_.Company -notin $InactiveStores -and $_.Amount -ne "0.00"}
$UNREC_S0 | Where-Object $NonAutoJournalCompanies | Export-Csv \\774512-LRBSPT01\*****$\uardata\rt1\BankRec\Test\step1\TestNonAutoJournal.txt -notype
$UNREC_S0 | Where-Object $AutoJournalCompanies | Export-Csv \\774512-LRBSPT01\*****$\uardata\rt1\BankRec\Test\step1\TestAutoJournal.txt -notype
$UNREC_S0 | Where-Object $ZeroValuelines | Export-Csv \\774512-LRBSPT01\*****$\uardata\rt1\BankRec\Test\step1\TestZeroLines.txt -notype
我遇到问题的数组是$ AutoJournalDescriptions.如果数组包含单个条件,则只能使它工作.否则,似乎将它们全部忽略. 在这里,它仅包含一对,但是#之后的条件也应包括在内. 我试图在#(Non)AutojournalCompanies文件中包括和排除这些标准,以便所有数据都被预先保留,但分开后可以定向到不同的处理流.
The Array I have issues with is the $AutoJournalDescriptions. I can only get it working if the array contains a single criteria. Otherwise, it seems to ignore them all. Here it only contains a couple, but the criterias after the # should be included too. I'm trying to include and exclude these criterias as part of #(Non)AutojournalCompanies files so that all data is preseverd, but separated and can then be directed towards different process streams.
也许我只是在尝试使用一个不打算那样工作的功能...? 我整天都在寻找解决方案,但无济于事. 我可以在文件生产条件中单独键入所有这些条件,但这会使读取变得繁重且难以维护.我希望在需要更改时丰富/修改数组.
Perhaps i'm simply trying to use a function that isn't meant to work that way...? I've been searching for a solution all day to no avail. I could type all those criterias individually in the file production criteria, but that makes it heavy to read and cumbersome to maintain. I would prefer to enrich/modify the array when changes are required.
我希望一切都说得通. 我对Powershell很陌生.
I hope that all makes sense. I'm pretty new to powershell.
非常感谢,
Antoine
推荐答案
-
为了与通配符模式(例如
*SALES BANKED*
)匹配,您需要-like
运算符;相比之下,-contains
执行平等比较(对每个数组元素隐式地-eq
).In order match against wildcard patterns (such as
*SALES BANKED*
), you need the-like
operator; by contrast,-contains
performs equality comparisons (implicit-eq
against each array element).虽然这些运算符(以及其他运算符,例如
-eq
和-match
)支持 input 值 [1] 的数组,但 比较操作数(通常是RHS)必须是标量(单值)-您无法将输入数组与 multiple 值.While these operators (along with others, such as
-eq
and-match
) support an array of input values[1], the comparison operand (typically, the RHS) must be a scalar (single value) - you cannot compare the input array against multiple values at the same time.In your scenario, your best bet is to use regexes (regular expressions) rather than wildcard expressions, and to combine them into a single regex with the alternation operator (
|
), so you can use a single-match
operation to test for multiple patterns:# Sample input $UNREC_S0 = [pscustomobject] @{ Description = 'A SALES BANKED baz' }, [pscustomobject] @{ Description = 'bar' }, [pscustomobject] @{ Description = 'STORE TRANFrom foo' }, [pscustomobject] @{ Description = 'unrelated' } # The filtering criteria: *regexes* to match against the descriptions, # combined into a single regex with the alternation operator, '|' $AutoJournalDescriptions = '^STORE TRANFrom ', 'SALES BANKED' -join '|' # Construct script blocks to use with `Where-Object` below. $NonAutoJournalCompanies = { $_.Description -notmatch $AutoJournalDescriptions } $AutoJournalCompanies = { $_.Description -match $AutoJournalDescriptions} $UNREC_S0 | Where-Object $NonAutoJournalCompanies | Export-Csv \\774512-LRBSPT01\*****$\uardata\rt1\BankRec\Test\step1\TestNonAutoJournal.txt -notype # ...
上面的代码产生了以下CSV数据,显示仅导出了与正则表达式不匹配的描述:
The above yields the following CSV data, showing that only the descriptions not matching the regexes were exported:
"Description" "bar" "unrelated"
请注意正则表达式
^STORE TRANFrom
如何对应于通配符表达式STORE TRANFrom *
,而SALES BANKED
对应于*SALES BANKED*
.Note how regex
^STORE TRANFrom
corresponds to wildcard expressionSTORE TRANFrom *
, andSALES BANKED
to*SALES BANKED*
.通配符
*
运算符-通常对应于正则表达式中的.*
-在此正则表达式中不需要,因为-match
运算符隐式执行 substring 匹配(而通配符-与-like
匹配与整个输入字符串匹配).The wildcard
*
operator - which normally correspond to.*
in a regex - isn't needed in the regexes here, because the-match
operator implicitly performs substring matching (whereas wildcard-matching with-like
matches against the whole input string).如果将条件公式化为 regexes (正则表达式),则可以使用
Select-String
cmdlet ,它支持操作数:If you formulate your criteria as regexes (regular expressions), you can use the
Select-String
cmdlet, which does support multiple comparison operands:# Sample input $descriptions = 'A SALES BANKED baz', 'bar', 'STORE TRANFrom foo', 'unrelated' # The filtering criteria: *regexes* to match against the descriptions. $descriptionRegexes = '^STORE TRANFrom ', 'SALES BANKED' ($descriptions | Select-String -Pattern $descriptionRegexes).Line
注意:您也可以使用
-SimpleMatch
而不是-Pattern
来使用此技术来查找文字子字符串 ,但是请注意然后在每个输入字符串中 wherewhere 匹配子字符串,而不能将匹配限制为例如字符串的开头.Note: You can also use this technique for finding literal substrings, by using
-SimpleMatch
instead of-Pattern
, but note that substrings are then matched anywhere in each input string, without being able to restrict matching to, say, the start of the string.上面的代码输出以下内容(一个2元素的数组):
The above outputs the following (a 2-element array):
A SALES BANKED baz STORE TRANFrom foo
您可以使用相似的方法,方法是将单独的正则表达式与备用(
|
)运算符组合到一个单独的正则表达式中,-match
运算符:
You can use a similar approach by combining the individual regexes into a single one with the alternation (
|
) operator, which enables use of the-match
operator:# Sample input $descriptions = 'A SALES BANKED baz', 'bar', 'STORE TRANFrom foo', 'unrelated' # The filtering criteria: *regexes* to match against the descriptions, # combined into a single regex with the alternation operator, '|' $descriptionRegex = '^STORE TRANFrom ', 'SALES BANKED' -join '|' # -> '^STORE TRANFrom |SALES BANKED' $descriptions -match $descriptionRegex
您还可以将该方法适应于文字子字符串匹配,即通过转义子字符串以在正则表达式中使用
[regex]::Escape()
;例如
$descriptionRegex = ('yes?', '2.0').ForEach({ [regex]::Escape($_) }) -join '|'
You can also adapt this approach to literal substring matching, namely by escaping the substrings for literal use inside a regex with
[regex]::Escape()
; e.g.,
$descriptionRegex = ('yes?', '2.0').ForEach({ [regex]::Escape($_) }) -join '|'
否则,如果您确实需要通配符支持,则必须-效率低下-巢循环 (如果您需要,请参见下面的快捷方式)可以做出特定的假设):
Otherwise, if you do need wildcard support, you'll have to - inefficiently - nest loops (see shortcut below, if you can make specific assumptions):
# Sample input $descriptions = 'A SALES BANKED baz', 'bar', 'STORE TRANFrom foo', 'unrelated' # The filtering criteria: wildcard patterns to match against the descriptions. $descriptionWildcards = 'STORE TRANFrom *', '*SALES BANKED*' foreach ($descr in $descriptions) { foreach ($wildcard in $descriptionWildcards) { if ($descr -like $wildcard) { $descr; break } } }
请注意,我使用的是
foreach
语句,而不是使用ForEach-Object
cmdlet 调用的管道;前者更快,如果输入流,后者可以使内存消耗保持恒定;如果数组已经在内存中,那么foreach
语句是更好的选择.Note that I've used
foreach
statements rather than the pipeline with aForEach-Object
cmdlet call; the former is faster, the latter can keep memory consumption constant if the input is being streamed; with arrays already in memory, in full, theforeach
statement is the better choice.如果可以做出两个假设,则可以采用快捷方式:
You can take a shortcut, IF you can make two assumptions:
-
没有单个通配符模式匹配个输入.
不需要保留输入顺序;也就是说,描述的输出顺序可以反映通配符模式数组中条目的顺序,而不是输入描述的顺序.
The input order needn't be preserved; that is, it is acceptable that the output order of descriptions reflects the order of the entries in the wildcard-pattern array, not the order of the input descriptions.
# Sample input $descriptions = 'A SALES BANKED baz', 'bar', 'STORE TRANFrom foo', 'unrelated' # The filtering criteria: wildcard patterns to match against the descriptions. $descriptionWildcards = 'STORE TRANFrom *', '*SALES BANKED*' # Loop over the criteria and match the descriptions against each. # `foreach` is the built-in alias for the `ForEach-Object` cmdlet. # The output order will be reflect the order of the wildcard patterns. $descriptionWildcards | foreach { $descriptions -like $_ }
在这种情况下,虽然所得元素相同,但是它们的顺序却不同:
In this case, while the resulting elements are the same, their ordering differs:
STORE TRANFrom foo A SALES BANKED baz
[1]使用值数组作为输入,这些运算符的作用类似于过滤器:也就是说,它们返回匹配值的子数组;例如,
1, 2, 3 -eq 2
返回2
作为单元素数组.
[1] With an array of values as input, these operators act like filters: that is, they return the sub-array of matching values; e.g.,
1, 2, 3 -eq 2
returns2
as a single-element array.这篇关于使用包含条件和通配符的数组时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
-