簡體   English   中英

不區分大小寫的字符串比較奇怪的行為

[英]Case-insenstive string comparison strange behavior

這在C#和Java中都會發生,所以我認為這不是一個bug,只是想知道為什么。

var s = "𐐁";
var lower = s.ToLower();
var upper = s.ToUpper();

if (!lower.Equals(upper, StringComparison.OrdinalIgnoreCase))
{
    //How can this happen?
}

根據這個頁面 ,“𐐁”的小寫字母是“𐐩”,與IgnoreCase選項相比,它們應該是相等的。 為什么他們不平等?

為了保護Java API: String.equalsIgnoreCase方法文檔從未聲稱它可以在任意Unicode代碼點上“按預期”工作。 它說:

如果至少滿足下列條件之一,則兩個字符c1和c2被視為相同的忽略大小寫:

  • 這兩個字符是相同的(通過==運算符進行比較)
  • 將Character.toUpperCase(char)方法應用於每個字符會產生相同的結果
  • 將Character.toLowerCase(char)方法應用於每個字符會產生相同的結果

因此,文檔非常明確地指出它將Character.toUpperCase應用於char ,即UTF-16 代碼單元 ,而不是Unicode代碼點。

如果在每個代碼上使用方法Character.toUpperCase(int codePoint) ,則比較將按預期運行。 下面是Scala中的一個簡短示例(使用完全相同的Java API,高階forall方法有望不言自明):

val a = "𐐁"
val b = "𐐩"
(a.codePoints.toArray zip b.codePoints.toArray).forall { 
  case (x, y) => 
  Character.toLowerCase(x) == Character.toLowerCase(y) 
}

版畫

true

正如所料。 為什么會這樣? 我認為可以安全地將此問題歸咎於向后兼容性。

當您將“𐐁”和“𐐩”同時轉換為其數值時,您可能會獲得更有趣的值。 您獲得與投射結果相同的整數值55297。 StringComparison.Ordinal基於字符的數值。 由於“序數”表示“基於數字”,並且兩個字符(大寫和小字母)在演員后具有相同的序數值,因此任何“基於數字”的比較將提供意外的結果。 OrdinalIgnoreCase顯然沒有為字符的大寫和小版本具有相同“序數”值的字符定義,以避免意外結果,並且在比較這些字符時會失敗(即導致錯誤)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM