IndexOf() 或 .FindIndex() 不区分大小写
IndexOf() or .FindIndex() case-insensitive
我正在尝试通过详细记录问题来验证一些 XML,包括所需的属性顺序和大写错误。如果所需的属性顺序是 one, two, three
并且有问题的 XML 有 one, three, two
我想记录它。如果一个属性只是错误地大写,说 TWO
而不是 two
我也想记录它。
目前我有两个数组,$ordered
包含属性名称(正确的大写)和 $miscapitalized
包含错误大写属性的名称。
因此,给定 one, three, TWO
的属性和 one, two, three
的所需顺序
$ordered = one, two, three
$miscapitalized = TWO
从这里我想追加错误的大写,所以一个新变量
$logged = one, two (TWO), three
我可以得到 $ordered
的索引,其中大写错误发生在
foreach ($attribute in $ordered) {
if ($attribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $attribute)
}
}
但是,我无法根据(正确大写的)$attribute
获取 $miscapitalized
中的索引。我试过了
$miscapitalized = @('one', 'two', 'three')
$miscapitalized.IndexOf('TWO')
这不起作用,因为 .IndexOf()
区分大小写。我发现 this 说 [Collections.Generic.List[Object]]
可以工作,所以我想也许 Generic.List 是功能的来源。所以我尝试了
$miscapitalized = [System.Collections.Generic.List[String]]@('one', 'two', 'three')
$miscapitalized.FindIndex('TWO')
哪个抛出
Cannot find an overload for "FindIndex" and the argument count: "1".
这让我想到 this 说我需要一个实际的谓词类型,而不仅仅是一个字符串。此时我已经不知所措,我唯一能想到的是 $miscapitalized.FindIndex([System.Predicate]::new('TWO'))
,但它不起作用。我怀疑 Predicate could/should 不知何故是一个正则表达式,但我似乎找不到任何指向正确方向的东西,或者至少我能理解并认识到它指向正确的方向。我还发现 https://www.powershellstation.com/2010/05/18/passing-predicates-as-parameters-in-powershell/
将代码块称为谓词,但我不清楚它与术语谓词的用法相同(这是一个广泛使用的术语),我也不知道如何制作代码块这在这里会有帮助。
我确实想出了这种方法,它在 $miscapitalized
中使用与在 $ordered
中相同的 foreach
搜索,并且确实有效。但我想知道是否有一种不需要嵌套循环的更优雅的方法。另外,理解这里应用的 Predicate 似乎很有用,以及(可能)如何使用代码块。
$ordered = @('one', 'two', 'three')
$miscapitalized = @('TWO')
$replacements = [System.Collections.Specialized.OrderedDictionary]::new()
foreach ($orderedAttribute in $ordered) {
if ($orderedAttribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $orderedAttribute)
foreach ($miscapitalizedAttribute in $miscapitalized) {
if (($miscapitalizedAttribute -iin $ordered) -and ($miscapitalizedAttribute -ieq $orderedAttribute) -and ($miscapitalizedAttribute -cne $orderedAttribute)) {
#$indexMiscapitalized = [array]::IndexOf($miscapitalized, $miscapitalizedAttribute)
$replacements.Add($indexOrdered, "$orderedAttribute ($miscapitalizedAttribute)")
}
}
}
}
if ($replacements.Count -gt 0) {
foreach ($index in $replacements.Keys) {
$ordered[$index] = $replacements.$index
}
}
$ordered
编辑:根据下面的评论,我试过了
$ordered = @('one', 'two', 'three')
$miscapitalized = @('TWO', 'Three')
$replacements = [System.Collections.Specialized.OrderedDictionary]::new()
foreach ($orderedAttribute in $ordered) {
if ($orderedAttribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $orderedAttribute)
if ($indexMiscapitalized = $miscapitalized.FindIndex({param($s) $s -eq $orderedAttribute})) {
$replacements.Add($indexOrdered, "$orderedAttribute ($($miscapitalized[$indexMiscapitalized]))")
}
}
}
if ($replacements.Count -gt 0) {
foreach ($index in $replacements.Keys) {
$ordered[$index] = $replacements.$index
}
}
$ordered
得到最后一个 (three/Three) 但缺少 two/TWO。但是明天可以尝试很多可能的解决方案,因为每个解决方案都可以学到一些东西。
也许,你想多了。您可以使用 Compare-Object 完成所有艰苦的工作,然后您可以检查结果并相应地记录它们:
# Reference array for attributes order and capitalization
[array]$reference = @(
'one'
'two'
'three'
'four'
)
# Example XML
[xml]$xml = '<foo one="1" oNe="oNe" thrEE="thrEE" two="2">dummy</foo>'
# Compare XML attributes to refrerence array
# -SyncWindow 0 - Order of items in the array matters
#
Compare-Object -ReferenceObject $reference -DifferenceObject $xml.foo.Attributes.Name -SyncWindow 0 -CaseSensitive -includeEqual
这将产生:
InputObject SideIndicator
----------- -------------
one ==
oNe =>
two <=
thrEE =>
three <=
two =>
four <=
如您所见,one
属性位于正确的索引处 (==
) 并且大小写正确。我们还有额外的 oNe
属性,这是不合适的。
您还可以对 Compare-Object
结果进行分组并生成哈希表,您可以将其用于高级日志记录。您可以使用 SideIndicator
和 InputObject
属性进行各种查找和比较。
$group = Compare-Object -ReferenceObject $reference -DifferenceObject $xml.foo.Attributes.Name -SyncWindow 0 -CaseSensitive -includeEqual |
Group-Object -Property InputObject -AsHashTable -AsString
$group
结果
four {@{InputObject=four; SideIndicator=<=}}
one {@{InputObject=one; SideIndicator===}, @{InputObject=oNe; SideIndicator==>}}
thrEE {@{InputObject=thrEE; SideIndicator==>}, @{InputObject=three; SideIndicator=<=}}
two {@{InputObject=two; SideIndicator=<=}, @{InputObject=two; SideIndicator==>}}
在这种情况下,哈希表键将不区分大小写,因此您可以这样做:
foreach ($r in $reference) {
$ret = $group.$r | Where-Object {
$_.SideIndicator -ne '==' -and $_.InputObject -cne $r
} | Select-Object -ExpandProperty InputObject |
ForEach-Object {
'Index of {0}: {1}' -f $_, $xml.foo.Attributes.Name.IndexOf($_)
}
if ($ret) {
@{ $r = $ret }
}
}
Name Value
---- -----
one Index of "oNe": 1
three Index of "thrEE": 2
您可以添加一个小的辅助函数来查找不区分大小写的索引:
function Find-Index {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string[]]$Array,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Value
)
for ($i = 0; $i -lt $Array.Count; $i++) {
if ($Array[$i] -eq $Value) { return $i }
}
-1
# or combine the elements with some unlikely string
# convert that to lowercase and split on the same unlikely string
# then use regular IndexOf() against the value which is also lower-cased:
# (($Array -join '~@~').ToLowerInvariant() -split '~@~').IndexOf($Value.ToLowerInvariant())
}
然后在下面,这样使用它:
# if any of the below arrays has only one item, wrap it inside @()
$ordered = 'one','two','three'
$miscapitalized = 'One','TWO'
$logged = foreach ($item in $ordered) {
$index = Find-Index $miscapitalized $item
if ($index -ge 0) {
'{0} ({1})' -f $item, $miscapitalized[$index]
}
else { $item }
}
$logged -join ','
输出
one (One),two (TWO),three
您可以用脚本块替换 FindIndex()
所需的谓词:
PS ~> $miscapitalized = [System.Collections.Generic.List[String]]@('one', 'two', 'three')
PS ~> $predicate = {param($s) $s -eq 'TWO'}
PS ~> $miscapitalized.FindIndex($predicate)
1
这将按预期工作,因为 PowerShell 的 -eq
运算符默认不区分大小写。
我正在尝试通过详细记录问题来验证一些 XML,包括所需的属性顺序和大写错误。如果所需的属性顺序是 one, two, three
并且有问题的 XML 有 one, three, two
我想记录它。如果一个属性只是错误地大写,说 TWO
而不是 two
我也想记录它。
目前我有两个数组,$ordered
包含属性名称(正确的大写)和 $miscapitalized
包含错误大写属性的名称。
因此,给定 one, three, TWO
的属性和 one, two, three
$ordered = one, two, three
$miscapitalized = TWO
从这里我想追加错误的大写,所以一个新变量
$logged = one, two (TWO), three
我可以得到 $ordered
的索引,其中大写错误发生在
foreach ($attribute in $ordered) {
if ($attribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $attribute)
}
}
但是,我无法根据(正确大写的)$attribute
获取 $miscapitalized
中的索引。我试过了
$miscapitalized = @('one', 'two', 'three')
$miscapitalized.IndexOf('TWO')
这不起作用,因为 .IndexOf()
区分大小写。我发现 this 说 [Collections.Generic.List[Object]]
可以工作,所以我想也许 Generic.List 是功能的来源。所以我尝试了
$miscapitalized = [System.Collections.Generic.List[String]]@('one', 'two', 'three')
$miscapitalized.FindIndex('TWO')
哪个抛出
Cannot find an overload for "FindIndex" and the argument count: "1".
这让我想到 this 说我需要一个实际的谓词类型,而不仅仅是一个字符串。此时我已经不知所措,我唯一能想到的是 $miscapitalized.FindIndex([System.Predicate]::new('TWO'))
,但它不起作用。我怀疑 Predicate could/should 不知何故是一个正则表达式,但我似乎找不到任何指向正确方向的东西,或者至少我能理解并认识到它指向正确的方向。我还发现 https://www.powershellstation.com/2010/05/18/passing-predicates-as-parameters-in-powershell/
将代码块称为谓词,但我不清楚它与术语谓词的用法相同(这是一个广泛使用的术语),我也不知道如何制作代码块这在这里会有帮助。
我确实想出了这种方法,它在 $miscapitalized
中使用与在 $ordered
中相同的 foreach
搜索,并且确实有效。但我想知道是否有一种不需要嵌套循环的更优雅的方法。另外,理解这里应用的 Predicate 似乎很有用,以及(可能)如何使用代码块。
$ordered = @('one', 'two', 'three')
$miscapitalized = @('TWO')
$replacements = [System.Collections.Specialized.OrderedDictionary]::new()
foreach ($orderedAttribute in $ordered) {
if ($orderedAttribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $orderedAttribute)
foreach ($miscapitalizedAttribute in $miscapitalized) {
if (($miscapitalizedAttribute -iin $ordered) -and ($miscapitalizedAttribute -ieq $orderedAttribute) -and ($miscapitalizedAttribute -cne $orderedAttribute)) {
#$indexMiscapitalized = [array]::IndexOf($miscapitalized, $miscapitalizedAttribute)
$replacements.Add($indexOrdered, "$orderedAttribute ($miscapitalizedAttribute)")
}
}
}
}
if ($replacements.Count -gt 0) {
foreach ($index in $replacements.Keys) {
$ordered[$index] = $replacements.$index
}
}
$ordered
编辑:根据下面的评论,我试过了
$ordered = @('one', 'two', 'three')
$miscapitalized = @('TWO', 'Three')
$replacements = [System.Collections.Specialized.OrderedDictionary]::new()
foreach ($orderedAttribute in $ordered) {
if ($orderedAttribute -iin $miscapitalized) {
$indexOrdered = [array]::IndexOf($ordered, $orderedAttribute)
if ($indexMiscapitalized = $miscapitalized.FindIndex({param($s) $s -eq $orderedAttribute})) {
$replacements.Add($indexOrdered, "$orderedAttribute ($($miscapitalized[$indexMiscapitalized]))")
}
}
}
if ($replacements.Count -gt 0) {
foreach ($index in $replacements.Keys) {
$ordered[$index] = $replacements.$index
}
}
$ordered
得到最后一个 (three/Three) 但缺少 two/TWO。但是明天可以尝试很多可能的解决方案,因为每个解决方案都可以学到一些东西。
也许,你想多了。您可以使用 Compare-Object 完成所有艰苦的工作,然后您可以检查结果并相应地记录它们:
# Reference array for attributes order and capitalization
[array]$reference = @(
'one'
'two'
'three'
'four'
)
# Example XML
[xml]$xml = '<foo one="1" oNe="oNe" thrEE="thrEE" two="2">dummy</foo>'
# Compare XML attributes to refrerence array
# -SyncWindow 0 - Order of items in the array matters
#
Compare-Object -ReferenceObject $reference -DifferenceObject $xml.foo.Attributes.Name -SyncWindow 0 -CaseSensitive -includeEqual
这将产生:
InputObject SideIndicator
----------- -------------
one ==
oNe =>
two <=
thrEE =>
three <=
two =>
four <=
如您所见,one
属性位于正确的索引处 (==
) 并且大小写正确。我们还有额外的 oNe
属性,这是不合适的。
您还可以对 Compare-Object
结果进行分组并生成哈希表,您可以将其用于高级日志记录。您可以使用 SideIndicator
和 InputObject
属性进行各种查找和比较。
$group = Compare-Object -ReferenceObject $reference -DifferenceObject $xml.foo.Attributes.Name -SyncWindow 0 -CaseSensitive -includeEqual |
Group-Object -Property InputObject -AsHashTable -AsString
$group
结果
four {@{InputObject=four; SideIndicator=<=}}
one {@{InputObject=one; SideIndicator===}, @{InputObject=oNe; SideIndicator==>}}
thrEE {@{InputObject=thrEE; SideIndicator==>}, @{InputObject=three; SideIndicator=<=}}
two {@{InputObject=two; SideIndicator=<=}, @{InputObject=two; SideIndicator==>}}
在这种情况下,哈希表键将不区分大小写,因此您可以这样做:
foreach ($r in $reference) {
$ret = $group.$r | Where-Object {
$_.SideIndicator -ne '==' -and $_.InputObject -cne $r
} | Select-Object -ExpandProperty InputObject |
ForEach-Object {
'Index of {0}: {1}' -f $_, $xml.foo.Attributes.Name.IndexOf($_)
}
if ($ret) {
@{ $r = $ret }
}
}
Name Value
---- -----
one Index of "oNe": 1
three Index of "thrEE": 2
您可以添加一个小的辅助函数来查找不区分大小写的索引:
function Find-Index {
param (
[Parameter(Mandatory = $true, Position = 0)]
[string[]]$Array,
[Parameter(Mandatory = $true, Position = 1)]
[string]$Value
)
for ($i = 0; $i -lt $Array.Count; $i++) {
if ($Array[$i] -eq $Value) { return $i }
}
-1
# or combine the elements with some unlikely string
# convert that to lowercase and split on the same unlikely string
# then use regular IndexOf() against the value which is also lower-cased:
# (($Array -join '~@~').ToLowerInvariant() -split '~@~').IndexOf($Value.ToLowerInvariant())
}
然后在下面,这样使用它:
# if any of the below arrays has only one item, wrap it inside @()
$ordered = 'one','two','three'
$miscapitalized = 'One','TWO'
$logged = foreach ($item in $ordered) {
$index = Find-Index $miscapitalized $item
if ($index -ge 0) {
'{0} ({1})' -f $item, $miscapitalized[$index]
}
else { $item }
}
$logged -join ','
输出
one (One),two (TWO),three
您可以用脚本块替换 FindIndex()
所需的谓词:
PS ~> $miscapitalized = [System.Collections.Generic.List[String]]@('one', 'two', 'three')
PS ~> $predicate = {param($s) $s -eq 'TWO'}
PS ~> $miscapitalized.FindIndex($predicate)
1
这将按预期工作,因为 PowerShell 的 -eq
运算符默认不区分大小写。