http://www.leeholmes.com/blog/2007/12/05/powershells-eq-operator-reference-equality-vs-value-equality/余り本件に関して書くことが無いのですが、一応簡単なサンプルを。
今回は、テキストに含まれるかどうか/比較を見る方法のメモです。
サンプル
今回、これらを試してみます。
"abc".Contains("a") "Abc".Contains("a") "" "abc" -contains "a" @("abc","bc","c") -contains "a" @("abc","bc","c") -contains "c" @("abc","bc","C") -contains "c" "" "abc" -ccontains "a" @("abc","bc","c") -ccontains "a" @("abc","bc","c") -ccontains "c" @("abc","bc","C") -ccontains "c" "" "a" -in "abc" "a" -in @("abc","bc","c") "c" -in @("abc","bc","c") "c" -in @("abc","bc","C") "" "a" -cin "abc" "a" -cin @("abc","bc","c") "c" -cin @("abc","bc","c") "c" -cin @("abc","bc","C") "" "abc" -match "a" "abc" -match "A" "abc" -cmatch "a" "abc" -cmatch "A" "" [regex]::Match("abc","a") "" "abc" -eq "a" "a" -eq "a" "A" -eq "a" "" "abc" -ceq "a" "a" -ceq "a" "A" -ceq "a" "" "abc".Equals("a") "a".Equals("a") "a".Equals("A") "" 'ー'.Contains('々') 'ー' -contains '々' 'ー' -ccontains '々' '々' -in 'ー' '々' -cin 'ー' 'ー' -match '々' 'ー' -cmatch '々' 'ー' -eq '々' 'ー' -ceq '々' 'ー'.Equals('々') [Object]::ReferenceEquals('ー', '々')
結果を見てみましょう。
True #"abc".Contains("a") False #"Abc".Contains("a") False #"abc" -contains "a" False #@("abc","bc","c") -contains "a" True #@("abc","bc","c") -contains "c" True #@("abc","bc","C") -contains "c" False #"abc" -ccontains "a" False #@("abc","bc","c") -ccontains "a" True #@("abc","bc","c") -ccontains "c" False #@("abc","bc","C") -ccontains "c" False #"a" -in "abc" False #"a" -in @("abc","bc","c") True #"c" -in @("abc","bc","c") True #"c" -in @("abc","bc","C") False #"a" -cin "abc" False #"a" -cin @("abc","bc","c") True #"c" -cin @("abc","bc","c") False #"c" -cin @("abc","bc","C") True #"abc" -match "a" True #"abc" -match "A" True #"abc" -cmatch "a" False #"Abc" -cmatch "A" #[regex]::Match("abc","a") Groups : {a} Success : True Captures : {a} Index : 0 Length : 1 Value : a False #"abc" -eq "a" True #"a" -eq "a" True #"A" -eq "a" False #"abc" -ceq "a" True #"a" -ceq "a" False #"A" -ceq "a" False #"abc".Equals("a") True #"a".Equals("a") False #"a".Equals("A") False #'ー'.Contains('々') True #'ー' -contains '々' True #'ー' -ccontains '々' True #'々' -in 'ー' True #'々' -cin 'ー' False #'ー' -match '々' False #'ー' -cmatch '々' True #'ー' -eq '々' True #'ー' -ceq '々' False #'ー'.Equals('々') False #[Object]::ReferenceEquals('ー', '々')
それぞれ見てみます。
contains()
このようなコードでした。
"abc".Contains("a") "Abc".Contains("a") 'ー'.Contains('々')
結果はこうですね
True #"abc".Contains("a") False #"Abc".Contains("a") False #'ー'.Contains('々')
動作は、そのままです。"Value".Contrains(x)の時、「Valueにxが含まれるか」をケースセンシティブに判定します。
-contains
このようなコードでした。
"abc" -contains "a" @("abc","bc","c") -contains "a" @("abc","bc","c") -contains "c" @("abc","bc","C") -contains "c" 'ー' -contains '々'
結果はこうですね
False #"abc" -contains "a" False #@("abc","bc","c") -contains "a" True #@("abc","bc","c") -contains "c" True #@("abc","bc","C") -contains "c" True #'ー' -contains '々'
.Contains()と異なるのが分かります。 @("Value1","Value2","Value3") -Contrains "x"の時、xが配列の要素"Value1"と"Value2"に含まれるかを判定します。
この判定は、配列要素との判定であり、配列の構成文字ではありません。
つまり、Value1="abc"とx="a"の場合は「"abc"に"a"が含まれるかどうかの判定ではありません」。.Contains()が、"abc"と"a"の場合は「"abc"に含まれるかどうか判定」であるため、.Contains()と-containsでは動作が違います。
-ccontains
このようなコードでした。
"abc" -ccontains "a" @("abc","bc","c") -ccontains "a" @("abc","bc","c") -ccontains "c" @("abc","bc","C") -ccontains "c" 'ー' -ccontains '々'
結果はこうですね
False #"abc" -ccontains "a" False #@("abc","bc","c") -ccontains "a" True #@("abc","bc","c") -ccontains "c" False #@("abc","bc","C") -ccontains "c" True #'ー' -ccontains '々'
-containsは、ケースセンシティブに判定しませんでした。 ケースセンシティブに判定するには、-ccontainsとします。
-in
このようなコードでした。
"a" -in "abc" "a" -in @("abc","bc","c") "c" -in @("abc","bc","c") "c" -in @("abc","bc","C") '々' -in 'ー'
結果はこうですね
False #"a" -in "abc" False #"a" -in @("abc","bc","c") True #"c" -in @("abc","bc","c") True #"c" -in @("abc","bc","C") True #'々' -in 'ー' False #[Object]::ReferenceEquals('ー', '々')
-inは、PowerShell 3.0から追加されました。 動作は、-containsのOperatorが逆になったものです。 "x" -in @("Value1","Value2","Value3") の時、xが配列の要素"Value1"と"Value2"に含まれるかを判定します。-containsに比べて、右辺と左辺が入れ替わっていることが分かります。
-cin
このようなコードでした。
"a" -cin "abc" "a" -cin @("abc","bc","c") "c" -cin @("abc","bc","c") "c" -cin @("abc","bc","C") '々' -cin 'ー'
結果はこうですね
False #"a" -cin "abc" False #"a" -cin @("abc","bc","c") True #"c" -cin @("abc","bc","c") False #"c" -cin @("abc","bc","C") True #'々' -cin 'ー'
-inは、ケースセンシティブに判定しませんでした。 ケースセンシティブに判定するには、-cinとします。
-match
このようなコードでした。
"abc" -match "a" "abc" -match "A" 'ー' -match '々'
結果はこうですね
True #"abc" -match "a" True #"Abc" -cmatch "a" False #'ー' -match '々'
動作はそのままです。"Value" -match "x"の時、正規表現でValueにxが含まれるかを判定します。
-cmatch
このようなコードでした。
"abc" -cmatch "a" "abc" -cmatch "A" 'ー' -cmatch '々'
結果はこうですね
True #"abc" -cmatch "a" False #"abc" -cmatch "A" False #'ー' -cmatch '々'
-matchはケースセンシティブに判定しませんでした。 ケースセンシティブに判定するには、-cmatchとします。
[regex]::Match()
このようなコードでした。
[regex]::Match("abc","a")
結果はこうですね
#[regex]::Match("abc","a") Groups : {a} Success : True Captures : {a} Index : 0 Length : 1 Value : a
動作は、そのままです。[regex]::Match("Value","x")の時、正規表現でValueにxが含まれるかをケースセンシティブ判定します。
-eq
このようなコードでした。
"abc" -eq "a" "a" -eq "a" "A" -eq "a" 'ー' -eq '々'
結果はこうですね
False #"abc" -eq "a" True #"a" -eq "a" True #"A" -eq "a" True #'ー' -eq '々'
動作は、そのままと思いきや、'ー'と'々'がTrueはトラップになりそう。
少し見てみましょう。ここによると、基本的には参照比較ではなく値比較ですが、SecureStringのように参照比較しかクラスにない場合は参照比較を行うようです。
PowerShell’s -EQ Operator: Reference Equality vs Value Equality
そしてここで詳しく解説されています。
PowerShell equality operator not a symmetric relation?
この理解が必要なようです。
-eq in PowerShell is not an equivalence relation.
動的型付けというのがポイントといえるようです。'ー'と'々'がTrueなのはbooleanにも癖があるようです。 これはどうなるでしょうか。
[ConsoleColor]::Black -eq $true $true -eq [ConsoleColor]::Black
結果です。
False True
順序を入れかえると結果が変わりました。 $nullに対しても、同様の癖があるようです。
配列時の-eqのフィルタ挙動と、$nullが含まれる際の動作については、牟田口先生の解説が参考になります。
$nullに関しては、「分からない」を示すものと考えればよさそうですね。 これについては、SQLの記事ですがbleis先生が参考になります。
Value -eq xの時に、Valueとxを比較する- 基本的には値比較だが、参照比較になりうる
- boolean/null判定する場合は、
$true -eq Valueあるいは$null -eq Valueのように順序に気を付ける - 配列で利用した場合にフィルタ動作する
-ceq
このようなコードでした。
"abc" -ceq "a" "a" -ceq "a" "A" -ceq "a" 'ー' -ceq '々'
結果はこうですね
False #"abc" -ceq "a" True #"a" -ceq "a" False #"A" -ceq "a" 'ー' -ceq '々'
-eqは、ケースセンシティブに判定しませんでした。 ケースセンシティブに判定するには、-ceqとします。
.Equals()
このようなコードでした。
"abc".Equals("a") "a".Equals("a") "a".Equals("A") 'ー'.Equals('々')
結果はこうですね
False #"abc".Equals("a") True #"a".Equals("a") False #"a".Equals("A") False #'ー'.Equals('々')
動作は、そのままですね。あー、良かった。 "Value".Equals(x) の時、Valueとxが一致するかをケースセンシティブに判定します。
[Object]::ReferenceEquals()
このようなコードでした。
[Object]::ReferenceEquals('ー', '々')
結果はこうですね
False #[Object]::ReferenceEquals('ー', '々')
動作は、そのままですね。[Object]::ReferenceEquals(Value, x)の時、Valueとxの参照先が一致するかを判定します。
まとめ
単純に文字列を比較するなら…この辺が適してそうですね。
.Contains() .Equals() -match [regex]::Match()
オブジェクトの比較時には -eqを頻繁に利用しますが、少し注意をした方がいいようです。