From 您链接的维基百科文章 https://en.wikipedia.org/wiki/Arabic_script_in_Unicode:
呈现形式的存在只是为了与旧标准兼容,目前不需要对文本进行编码。
换句话说,您应该只使用通用形式(即 0600–06FF 范围代码点),而不是 FE70–FEFF 代码点范围的表示形式。请注意,您的示例字符串 ФдЮиеك 仅由 06xx 个字符组成,至少是浏览器给我的。
如果您有 FE70–FEFF 字符的旧源,请不要尝试修复它们的顺序,而只需通过将字符串转换为规范形式来删除表示信息。例如。
String s = "\uFE97\uFE98\uFE97\uFE96\uFE98";
System.out.println(s);
s = Normalizer.normalize(s, Normalizer.Form.NFKD);
System.out.println(s);
System.out.println(s.chars().mapToObj(i -> String.format("\\u%04X", i))
.collect(Collectors.joining("", "\"", "\"")));
打印
ﺗﺘﺗﺖﺘ
تتتتت
"\u062A\u062A\u062A\u062A\u062A"
该示例的源字符串故意弄乱了表示形式字符,以显示如何仅获取没有表示信息、仅由通用 U+062A 字符的重复组成的字符串来解决问题。换句话说,通用字符串被正确打印。
这种处理是通过字体完成的,该功能称为字形整形。我们可以看到它的实际效果,例如和
Font font = new Font("DejaVu Sans", 0, 48); // or Droid Sans Arabic
FontRenderContext frc = new FontRenderContext(null, true, false);
String s = "\u062A\u062A\u062A";
System.out.println(s);
if(font.canDisplayUpTo(s) >= 0) {
System.out.println("can't display string");
System.exit(0);
}
GlyphVector g = font.layoutGlyphVector(frc,
s.toCharArray(), 0, s.length(), Font.LAYOUT_RIGHT_TO_LEFT);
Rectangle r = g.getPixelBounds(frc, 0, 0);
System.out.println("Total width " + r.width);
for(int i = 0, n = g.getNumGlyphs(); i < n; i++) {
int chPos = g.getGlyphCharIndex(i);
System.out.printf("%2d (U+%04X) glyph code %4d, width %.0f%n",
chPos,(int)s.charAt(chPos),g.getGlyphCode(i),g.getGlyphMetrics(i).getAdvance());
}
BufferedImage bi = new BufferedImage(r.width, r.height, BufferedImage.TYPE_BYTE_BINARY);
Graphics2D gfx = bi.createGraphics();
//System.out.println(r);
gfx.drawGlyphVector(g, -r.x, -r.y);
gfx.dispose();
for(int line = 0, nLines = r.height; line < nLines; line++) {
for(int ch = 0, nChars = r.width; ch < nChars; ch++) {
System.out.print((bi.getRGB(ch, line) & 0xff) > 0? 'X': ' ');
}
System.out.println();
}
System.out.println();
在线尝试一下! https://tio.run/##hVRtb9owEP7OrzhFYjgiDaiqpmm0m6B0HVLXVpRWRduETOIkZsFBtlOCJn47OwdoE0i1fEjse3nu7vHjzOgLPZn5fzYbPl8kUsMMDS5davdbInSndmi9lnQRcU@d9o99Q@ZpKsKYHbsCBMsRh0z4TF7iimX6nbjreLWInhAskccRfE5D5vbSIGCS@QOz69RqNS@mSoGpcJXR@SJm8LcG@CzSacw9UJpq/Lwk3Ic55YI8aMlF@PM3UBkqexdsHgMBpg24AMGW@Z5YfTajTyk8UKEsB9oOnH2yO9BqQSKhLw2qcUFX0in3SlilgSGQXgG35CMijWMHtEyZAwGNFbNxsD3Utl9QmG39StsfT7vFt9V5C1wpzeZukmp3gSk6FkQVgXhAcpI9KvpcLWK6elyMEoyBLxfQLjLxDpqFmQ0N/jYZmTWNWXanKo9lXJN2wbd@XRUOGUKcKm8KAbFUwUWQMKeErFydXEZUdqWkK2Lnh6HcmIlQR2ZreHVvuuO7x9FkOLj@PpqM7iY3V99GRRJelQoSS4duyPQ9z1jcS1Lhq7yowS12XsXEKNE0hiX3dQQWNEG6@bqQFeAIGAwcyyCg2Fe7Tef5lIqgjDicg8BPs3lIv0n1ovtE7fPyJDP@AJWTEV5N@2uTAbHqpz6Qx2a9ffZsQ2jSwUt8BvUz39m1XnfbQV1YZZ7Nk5d2zAC2cj1Duia5zXYK3SAaNlKw/GCoCU@h0Zi6/gsVHiN2pQxKFxmmfHc7Smay49VBgiPGw0g75QB3NL6/mvTGI3wNbrvDcaHU2w8LwiBD@Cl3PcmoZnsPKUS3WhXnLAsBiOH6ki6LGg0dOJFulr9Xh7F4TRLFSIUmYi7YThY3uDRnvJ@vs3We7zzb7bE89khetMMxytji5IR1jOd8ZzabY4gq1RCCHOHJDa97eNxOXtyGD9DOggB/E9D@Co3nxmdoQONAf@v//TwqNfB@3Lq23mz@AQ
تتت
Total width 70
2 (U+062A) glyph code 5261, width 47
1 (U+062A) glyph code 5263, width 14
0 (U+062A) glyph code 5262, width 13
XX XX XX XX
XXXX XXXX XXXX XXXX
XXXX XXXX XXXX XXXX
XXXX XXXX XXXX XXXX
XX XX
XXXX XXXX
XXXX XXXX
XXXX XXXX XXXX
XXXX
XXXX XXXXX XXXX XXXX
XXXX XXXXX XXXX XXXX
XXXXX XXXXX XXXX XXXX
XXXX XXXXX XXXX XXXX
XXXX XXXXX XXXX XXXX
XXXX XXXXXX XXXX XXXX
XXXXX XXXXXXXX XXXX XXXX
XXXXX XXXXXXXXXXX XXXXXX XXXXX
XXXXXX XXXXXXXXXXXXX XXXXXX XXXXX
XXXXXXXX XXXXXXXXXXX XXXXXX XXXXXXXXXX XXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXXX
XXXXXXXXXXXXXXXX XXXXXXXXX XXXXXXXXXX
请注意,实际的字形数量完全取决于特定的字体。例如,某些字体将中间的 Ê 字符映射到与最后一个字符相同的字形 - 纯粹的风格选择。
该程序仅用于演示相同的代码点(在本例中,char
就足够了)可能会映射到不同的字体特定字形。