Java 和 C 之间的代码点不匹配
Codepoint mismatch between Java and C
因此,我在将 imgui 端口中的以下字符 –
转为 kotlin
时遇到了一些问题
在对字符集和编码进行了一整天的研究之后,我只剩下了唯一的希望:依靠 unicode 代码点。
jvm 上的那个字符
"–"[0].toInt() // same as codePointAt()
returns 代码点 u2013
在 C 上,我不确定,但因为这就是 done:
const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
{
if (c >= IndexLookup.Size)
return FallbackGlyph;
const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1)
return FallbackGlyph;
return &Glyphs.Data[i];
}
哪里
typedef unsigned short ImWchar
和
ImVector<ImWchar> IndexLookup; // Sparse. Index glyphs by Unicode code-point.
所以,这样做
char* a = "–";
int b = a[0];
returns 代码点 u0096
据我所知,在 127
(0x7F
) 之后,我们似乎处于 "Extended Ascii" 区域,这很糟糕,因为看起来有不同的 [=其中 72=]。
例如,这个 encoding table doesn't match my codepoint, but the Cp1252 encoding 确实如此,所以我倾向于认为这就是 C 上实际使用的东西。
在刚刚提到的link最下面的table中,其实可以看到150
(十进制,从给定数的右栏开始数)确实是对应的到 2013
(十六进制,我发现它有点不连贯,但无论如何)。
为了解决这个问题,我尝试将我在 Kotlin 上的 String
转换为相同的编码(暂时忽略这当然是特定于平台的),所以对于每个 c: Char
"$c".toByteArray(Charset.forName("Cp1252"))[0].toUnsignedInt
这有效,但会破坏外国字体的渲染,例如中文、日文等。
所以,我的问题是:为什么 JVM 上的 u2013
和 C 上的 u0096
有区别?
处理这个问题的正确方法是什么?
目前我在 Windows 上解决了 this,我在检索 char 代码点之前插入了这个函数。
它基本上重新映射所有与 ISO-8859-1 不同的字符。你可以在这个table里面看到,都是那个浅灰色边框的
internal fun Char.remapCodepointIfProblematic(): Int {
val i = toInt()
return when (Platform.get()) {
/* https://en.wikipedia.org/wiki/Windows-1252#Character_set
* manually remap the difference from ISO-8859-1 */
Platform.WINDOWS -> when (i) {
// 8_128
0x20AC -> 128 // €
0x201A -> 130 // ‚
0x0192 -> 131 // ƒ
0x201E -> 132 // „
0x2026 -> 133 // …
0x2020 -> 134 // †
0x2021 -> 135 // ‡
0x02C6 -> 136 // ˆ
0x2030 -> 137 // ‰
0x0160 -> 138 // Š
0x2039 -> 139 // ‹
0x0152 -> 140 // Œ
0x017D -> 142 // Ž
// 9_144
0x2018 -> 145 // ‘
0x2019 -> 146 // ’
0x201C -> 147 // “
0x201D -> 148 // ”
0x2022 -> 149 // •
0x2013 -> 150 // –
0x2014 -> 151 // —
0x02DC -> 152 // ˜
0x2122 -> 153 // ™
0x0161 -> 154 // š
0x203A -> 155 // ›
0x0153 -> 156 // œ
0x017E -> 158 // ž
0x0178 -> 159 // Ÿ
else -> i
}
else -> i // TODO
}
}
因此,我在将 imgui 端口中的以下字符 –
转为 kotlin
在对字符集和编码进行了一整天的研究之后,我只剩下了唯一的希望:依靠 unicode 代码点。
jvm 上的那个字符
"–"[0].toInt() // same as codePointAt()
returns 代码点 u2013
在 C 上,我不确定,但因为这就是 done:
const ImFontGlyph* ImFont::FindGlyph(ImWchar c) const
{
if (c >= IndexLookup.Size)
return FallbackGlyph;
const ImWchar i = IndexLookup.Data[c];
if (i == (ImWchar)-1)
return FallbackGlyph;
return &Glyphs.Data[i];
}
哪里
typedef unsigned short ImWchar
和
ImVector<ImWchar> IndexLookup; // Sparse. Index glyphs by Unicode code-point.
所以,这样做
char* a = "–";
int b = a[0];
returns 代码点 u0096
据我所知,在 127
(0x7F
) 之后,我们似乎处于 "Extended Ascii" 区域,这很糟糕,因为看起来有不同的 [=其中 72=]。
例如,这个 encoding table doesn't match my codepoint, but the Cp1252 encoding 确实如此,所以我倾向于认为这就是 C 上实际使用的东西。
在刚刚提到的link最下面的table中,其实可以看到150
(十进制,从给定数的右栏开始数)确实是对应的到 2013
(十六进制,我发现它有点不连贯,但无论如何)。
为了解决这个问题,我尝试将我在 Kotlin 上的 String
转换为相同的编码(暂时忽略这当然是特定于平台的),所以对于每个 c: Char
"$c".toByteArray(Charset.forName("Cp1252"))[0].toUnsignedInt
这有效,但会破坏外国字体的渲染,例如中文、日文等。
所以,我的问题是:为什么 JVM 上的 u2013
和 C 上的 u0096
有区别?
处理这个问题的正确方法是什么?
目前我在 Windows 上解决了 this,我在检索 char 代码点之前插入了这个函数。 它基本上重新映射所有与 ISO-8859-1 不同的字符。你可以在这个table里面看到,都是那个浅灰色边框的
internal fun Char.remapCodepointIfProblematic(): Int {
val i = toInt()
return when (Platform.get()) {
/* https://en.wikipedia.org/wiki/Windows-1252#Character_set
* manually remap the difference from ISO-8859-1 */
Platform.WINDOWS -> when (i) {
// 8_128
0x20AC -> 128 // €
0x201A -> 130 // ‚
0x0192 -> 131 // ƒ
0x201E -> 132 // „
0x2026 -> 133 // …
0x2020 -> 134 // †
0x2021 -> 135 // ‡
0x02C6 -> 136 // ˆ
0x2030 -> 137 // ‰
0x0160 -> 138 // Š
0x2039 -> 139 // ‹
0x0152 -> 140 // Œ
0x017D -> 142 // Ž
// 9_144
0x2018 -> 145 // ‘
0x2019 -> 146 // ’
0x201C -> 147 // “
0x201D -> 148 // ”
0x2022 -> 149 // •
0x2013 -> 150 // –
0x2014 -> 151 // —
0x02DC -> 152 // ˜
0x2122 -> 153 // ™
0x0161 -> 154 // š
0x203A -> 155 // ›
0x0153 -> 156 // œ
0x017E -> 158 // ž
0x0178 -> 159 // Ÿ
else -> i
}
else -> i // TODO
}
}