【问题标题】:Golang strings.EqualFold gives unexpected resultsGolang strings.EqualFold 给出了意想不到的结果
【发布时间】:2021-12-17 20:28:33
【问题描述】:

在 golang (go1.17 windows/amd64) 中,下面的程序给出以下结果:

rune1 = U+0130 'İ'
rune2 = U+0131 'ı'
lower(rune1) = U+0069 'i'
upper(rune2) = U+0049 'I'
strings.EqualFold(İ, ı) = false
strings.EqualFold(i, I) = true

我认为strings.EqualFold 会在 Unicode 大小写折叠下检查字符串是否相等;然而,上面的例子似乎给出了一个反例。显然,两个符文都可以(手动)折叠成大小写相同的代码点。

问题strings.EqualFold(İ, ı)false 的 golang 是否正确?我预计它会产生true。如果 golang 是正确的,为什么会这样呢?或者这种行为是否符合某些 Unicode 规范。

我在这里错过了什么。


程序:

func TestRune2(t *testing.T) {
   r1 := rune(0x0130) // U+0130 'İ'
   r2 := rune(0x0131) // U+0131 'ı'
   r1u := unicode.ToLower(r1)
   r2u := unicode.ToUpper(r2)

   t.Logf("\nrune1 = %#U\nrune2 = %#U\nlower(rune1) = %#U\nupper(rune2) = %#U\nstrings.EqualFold(%s, %s) = %v\nstrings.EqualFold(%s, %s) = %v",
      r1, r2, r1u, r2u, string(r1), string(r2), strings.EqualFold(string(r1), string(r2)), string(r1u), string(r2u), strings.EqualFold(string(r1u), string(r2u)))
}

【问题讨论】:

    标签: go unicode case-insensitive


    【解决方案1】:

    是的,这是“正确”的行为。这些字母在大小写折叠下表现不正常。看: http://www.unicode.org/Public/UCD/latest/ucd/CaseFolding.txt

    U+0131 有全箱折叠“F”和特殊“T”:

    T: special case for uppercase I and dotted uppercase I
       - For non-Turkic languages, this mapping is normally not used.
       - For Turkic languages (tr, az), this mapping can be used instead
         of the normal mapping for these characters.
         Note that the Turkic mappings do not maintain canonical equivalence
         without additional processing.
         See the discussions of case mapping in the Unicode Standard for more information.
    

    我认为没有办法强制包字符串使用 tr 或 az 映射。

    【讨论】:

      【解决方案2】:

      来自 strings.EqualFold 源 - unicode.ToLowerunicode.ToUpper 未被使用。

      相反,它使用unicode.SimpleFold 来查看特定符文是否“可折叠”并因此具有可比性:

      // General case. SimpleFold(x) returns the next equivalent rune > x
      // or wraps around to smaller values.
      r := unicode.SimpleFold(sr)
      for r != sr && r < tr {
          r = unicode.SimpleFold(r)
      }
      

      符文İ 不可折叠。它的小写代码点是:

      r := rune(0x0130)        // U+0130 'İ'
      lr := unicode.ToLower(r) // U+0069 'i'
      
      fmt.Printf("foldable? %v\n", r != unicode.SimpleFold(r))   // foldable? false
      fmt.Printf("foldable? %v\n", lr != unicode.SimpleFold(lr)) // foldable? true
      

      如果一个符文是不可折叠的(即SimpleFold 返回自己) - 那么该符文只能匹配自己而不能匹配其他代码点。

      https://play.golang.org/p/105x0I714nS

      【讨论】:

        猜你喜欢
        • 2019-05-19
        • 2017-01-05
        • 2021-10-14
        • 1970-01-01
        • 1970-01-01
        • 2021-04-22
        • 2016-02-13
        • 2017-11-05
        • 1970-01-01
        相关资源
        最近更新 更多