Java的String.format
似乎没有意识到全角字符,例如日语或中文:
System.out.println(String.format("%1$9s: %2$20s : %3$20s\n", "field", "expected", "actual"));
System.out.println(String.format("%1$9s: %2$20s : %3$20s\n", "surface", "駆け", "駆け"));
输出未正确对齐:
field: expected : actual
surface: 駆け : 駆け
是否有使用String.format
格式化全角字符的正确方法?如果不是,是否有其他方法或库能够正确执行此操作?
答案 0 :(得分:0)
Java的String.format()
没有问题,因为它无法“知道”您要如何呈现文本或将使用的字体。它的作用纯粹是组装格式化的文本字符串以随后显示。格式化文本的视觉外观(主要)由显示字体控制,开发人员必须相应地明确设置格式。
一种简单的解决方案是使用一种字体,该字体同时显示具有恒定宽度字形的拉丁字符和CJK字符,但我找不到。有关更多详细信息,请参见Unicode Technical Report titled "East Asian Width":
对于传统的东亚固定螺距字体,此宽度表示 调整为显示宽度的一半或整个单位宽度。普通的 该单位宽度的名称为“ Em”。虽然Em通常是 字母“ M”的高度,与东方的单位宽度相同 亚洲字体,因为在这些字体中,标准字符单元格为 广场。 相反,固定间距拉丁字体的字符宽度 例如Courier通常是Em的3/5。
我猜测可能没有任何等宽字体显示相同宽度的CJK字符和拉丁字符,只是因为它看起来很奇怪。例如,假设两个拉丁字符“ li”与两个日语字符“駆け”占据相同的宽度。因此,即使您使用等宽字体来呈现拉丁字符和CJK字符,尽管每种语言的字符都是等距的,但每种语言的宽度可能仍然不同。
Google有一个very helpful site for evaluating their fonts,可让您:
输入所需的任何文本,并将其应用于所有选定的字体以进行比较。例如,此屏幕快照显示了 AEIOUY 的拉丁字形与使用不同字体的某些日语字形的外观。请注意,拉丁字形的宽度始终较小,尽管数量有所变化,具体取决于所使用的字体和要呈现的特定字形:
以下是可能的解决对齐问题的方法:
因此,在代码中,将前导空格的数量减少了要呈现的日语字形的数量:
System.out.println("* The display font is named MotoyaLMaru, created by installing Google font KosugiMaru-Regular.ttf.");
System.out.println("* With this font Japanese glyphs seem to be twice the width of Latin glyphs.");
System.out.println("* Downloaded from https://fonts.google.com/specimen/Kosugi+Maru?selection.family=Kosugi+Maru");
System.out.println(" ");
System.out.println(String.format("%1$9s: %2$20s : %3$20s\n", "field", "expected", "actual"));
System.out.println(String.format("%1$9s: %2$18s : %3$18s\n", "surface", "駆け", "駆け")); // 18, not 20!
System.out.println(String.format("%1$9s: %2$12s : %3$12s\n", "1234567", "川土空田天生花草", "川土空田天生花草")); // 12, not 20!
这是在Windows 10的NetBeans中运行该代码的输出,显示了正确对齐的列:
注意: