【问题标题】:Issue using an array containing criteria with wildcards使用包含通配符条件的数组时出现问题
【发布时间】:2019-10-31 16:57:19
【问题描述】:

我一直在尝试运行 powershell 代码将文件拆分为 2。

我有几个常规数组,效果很好。 第三个数组包含每个条件的通配符,这根本不起作用。

我尝试过 -in -notin、-like -notlike、-contains -notcontains、-match -notmatch,但没有得到我想要的结果。

    $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 文件的一部分包含和排除,以便所有数据都被保留,但可以分开,然后可以定向到不同的流程流。

也许我只是想使用一个不应该以这种方式工作的功能......? 我整天都在寻找解决方案,但无济于事。 我可以在文件制作标准中单独键入所有这些标准,但这会使阅读变得繁重且维护起来很麻烦。我更愿意在需要更改时丰富/修改数组。

我希望一切都有意义。 我对powershell很陌生。

非常感谢,

安东尼

【问题讨论】:

  • 对于通配符,您需要使用-like-notlike。由于-match-notmatch 使用正则表达式,* 是一个特殊字符。在正则表达式中,-match 'sales banked' 将匹配与 -like "*sales banked*" 相同的结果
  • 顺便说一句,您不需要 @( ) 来制作数组。

标签: arrays powershell wildcard


【解决方案1】:
  • 为了匹配通配符模式(例如*SALES BANKED*),你需要-like操作符;相比之下,-contains 执行 相等 比较(隐式 -eq 针对每个数组元素)。

  • 虽然这些运算符(以及其他运算符,例如 -eq-match)支持 输入 值数组[1],但 比较操作数(通常是 RHS)必须是 标量(单个值) - 您不能将输入数组与 多个进行比较em> 值。


在您的场景中,您最好的选择是使用 regexes (regular expressions) 而不是通配符表达式,并将它们与交替运算符组合成一个 single 正则表达式(|),因此您可以使用单个 -match 操作来测试多个模式:

# 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 数据,表明仅导出了与正则表达式匹配的描述

"Description"
"bar"
"unrelated"

注意正则表达式 ^STORE TRANFrom 如何对应通配符表达式 STORE TRANFrom *,以及 SALES BANKED 对应于 *SALES BANKED*

通配符* 运算符 - 通常对应于正则表达式中的 .* - 在此处的正则表达式中不需要,因为 -match 运算符隐式执行 substring 匹配(而通配符-matching with -like 匹配整个输入字符串)。


可选阅读:通过子字符串或模式数组过滤字符串值数组:

如果您将标准制定为正则表达式(正则表达式),则可以使用Select-String cmdlet,它确实支持多重比较操作数:

# 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,但请注意然后在每个输入字符串中任何地方匹配子字符串,而不能将匹配限制在字符串的开头。

上面的输出如下(一个2元素数组):

A SALES BANKED baz
STORE TRANFrom foo

您可以使用类似的方法,将各个正则表达式组合与交替 (|) 运算符一起使用,这可以使用-match运营商

# 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 '|'


否则,如果您确实需要 通配符 支持,您将不得不 - 低效 - 嵌套循环(如果您需要,请参阅下面的快捷方式可以做出具体假设):

# 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 语句是更好的选择。


如果你能做出两个假设,你可以选择捷径

  • 没有单个通配符模式匹配多个输入。

  • 不需要保留输入顺序;也就是说,描述的输出顺序反映通配符模式数组中条目的顺序是可以接受的,而不是输入描述的顺序。

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

在这种情况下,虽然结果元素相同,但它们的顺序不同:

STORE TRANFrom foo
A SALES BANKED baz

[1] 将值数组作为输入,这些运算符的作用类似于过滤器:也就是说,它们返回匹配值的子数组;例如,1, 2, 3 -eq 22 作为单元素数组返回。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-05
    • 2019-07-04
    • 2013-11-06
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多