【问题标题】:Filtering characters missing from the user’s font in Java在 Java 中过滤用户字体中缺少的字符
【发布时间】:2012-03-01 22:05:44
【问题描述】:

我想用 Java 构建一个稍微简单的表(作为练习)来检查最终用户字体中是否存在合法的可打印 Unicode 代码点。因为某些字体无法打印有效的代码点,我必须知道用户的字体缺少哪些可打印的代码点,因此无法打印。

例如,如果字体仅支持拉丁字符,我无法使用它打印希腊字符,更不用说日文字符了。 Unicode 说它们都是可打印的,但用户的字体可能不够好。

经过一些研究,我已经能够在 Eclipse 中打印大部分字符(通过调整编码)。但是,我的输出中仍然有一堆未知/不可打印的字符,因为当我查看输出时,我会看到所有这些空矩形用于我的一些可打印字符。

我已尝试过滤它们,但找不到任何方法。仅供参考,我基本上只是将字符的值设置为 50、100 或 1000,然后通过for 循环从那里增加它以检查我可以或不能(或不应该)打印哪些字符。

谁能给我一些关于从哪里开始的提示?

【问题讨论】:

  • 定义“不可打印”。您是指不应该有任何可见渲染的字符(控制字符),还是指在所使用的字体中缺少字形的字符?还要定义“性格”。您是指分配给字符的代码单元、代码点还是代码点? (“Java 字符”,例如代码单元。)
  • @JukkaK.Korpela 比这更糟。有时,单个用户可见字符(读取,grapheme 或 Unicode 用语中的 extended grapheme cluster)包含多个代码点,例如在组合标记和其他 Grapheme_Extend 代码时涉及点数。

标签: java unicode fonts filter non-printable


【解决方案1】:

您的任务实际上比编码复杂一点,因为您尝试打印的字体会对输出产生很大影响。 IE。并非所有字体都支持相同的字符集。其实支持字符范围differs wildly from font to font

也就是说,您的问题现在变成了:如何检测某种字体是否支持给定字符?还有that question has been asked and answered...See here for the Java doc of the canDisplay 函数,它是the Font class 的成员。

【讨论】:

    【解决方案2】:

    目前尚不清楚您在这里的实际和确切含义。如果您打算按数字玩,那么Annex C of Unicode Technical Standard #18 on Unicode Regular Expressions 给出了具体建议,即“可打印”代码点定义为具有print 属性的任何代码点,其中该属性被定义为

    • \p{print} 表示 [[\p{graph}\p{blank}]&&[^\p{gc=Control}]]
    • \p{graph} 表示 [^\p{Whitespace}\p{gc=Control}\p{gc=Surrogate}\p{gc=Unassigned}]
    • \p{blank} 表示 [\p{Whitespace}&&[^\N{LF}\N{VT}\N{FF}\N{CR}\N{NEL}\p{gc=Line_Separator}\{gc=Paragraph_Separator}]

    或者,as the Java 1.7 Pattern class documents these,前提是您编译模式时启用了the new-to-Java7 Pattern.UNICODE_CHARACTER_CLASS 标志:

    • \p{Graph}可见字符:[^\p{IsWhite_Space}\p{gc=Cc}\p{gc=Cs}\p{gc=Cn}]
    • \p{Print} 可打印字符:[\p{Graph}\p{Blank}&&[^\p{Cntrl}]]
    • \p{Blank} 空格或制表符:[\p{IsWhite_Space}&&[^\p{gc=Zl}\p{gc=Zp}\x0a\x0b\x0c\x0d * \x85]]
    • \p{Cntrl}一个控制字符:\p{gc=Cc}
    • \p{XDigit} 十六进制数字:[\p{gc=Nd}\p{IsHex_Digit}]
    • \p{Space} 空格字符:\p{IsWhite_Space}

    关于“可打印”字符

    如果你只是使用一些合理的东西,比如 Java 的 (?U)\p{print} 模式属性(或 Character 类的等价物),那么你仍然需要做出一些“有趣”的决定。

    考虑以下每个代码点:

    U+000007 gc=Cc columns=0 print=0 graph=0  ALERT
    U+000008 gc=Cc columns=0 print=0 graph=0  BACKSPACE
    U+000009 gc=Cc columns=0 print=0 graph=0  CHARACTER TABULATION
    U+00000C gc=Cc columns=0 print=0 graph=0  FORM FEED (FF)
    U+00000D gc=Cc columns=0 print=0 graph=0  CARRIAGE RETURN (CR)
    U+000020 gc=Zs columns=1 print=1 graph=0  SPACE
    U+000021 gc=Po columns=1 print=1 graph=1  EXCLAMATION MARK
    U+000041 gc=Lu columns=1 print=1 graph=1  LATIN CAPITAL LETTER A
    U+000061 gc=Ll columns=1 print=1 graph=1  LATIN SMALL LETTER A
    U+000080 gc=Cc columns=0 print=0 graph=0  PADDING CHARACTER
    U+000085 gc=Cc columns=0 print=0 graph=0  NEXT LINE (NEL)
    U+00008D gc=Cc columns=0 print=0 graph=0  REVERSE LINE FEED
    U+0000AB gc=Pi columns=1 print=1 graph=1  LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
    U+0000AD gc=Cf columns=0 print=1 graph=1  SOFT HYPHEN
    U+0002B0 gc=Lm columns=1 print=1 graph=1  MODIFIER LETTER SMALL H
    U+0002C6 gc=Lm columns=1 print=1 graph=1  MODIFIER LETTER CIRCUMFLEX ACCENT
    U+000302 gc=Mn columns=0 print=1 graph=1  COMBINING CIRCUMFLEX ACCENT
    U+00036A gc=Mn columns=0 print=1 graph=1  COMBINING LATIN SMALL LETTER H
    U+001100 gc=Lo columns=2 print=1 graph=1  HANGUL CHOSEONG KIYEOK
    U+002028 gc=Zl columns=0 print=0 graph=0  LINE SEPARATOR
    U+002029 gc=Zp columns=0 print=0 graph=0  PARAGRAPH SEPARATOR
    U+00202B gc=Cf columns=0 print=1 graph=1  RIGHT-TO-LEFT EMBEDDING
    U+00202F gc=Zs columns=1 print=1 graph=0  NARROW NO-BREAK SPACE
    U+002060 gc=Cf columns=0 print=1 graph=1  WORD JOINER
    U+002061 gc=Cf columns=0 print=1 graph=1  FUNCTION APPLICATION
    U+002062 gc=Cf columns=0 print=1 graph=1  INVISIBLE TIMES
    U+002064 gc=Cf columns=0 print=1 graph=1  INVISIBLE PLUS
    U+002EC1 gc=So columns=2 print=1 graph=1  CJK RADICAL TIGER
    U+002F0B gc=So columns=2 print=1 graph=1  KANGXI RADICAL EIGHT
    U+003000 gc=Zs columns=2 print=1 graph=0  IDEOGRAPHIC SPACE
    U+003008 gc=Ps columns=2 print=1 graph=1  LEFT ANGLE BRACKET
    U+00300A gc=Ps columns=2 print=1 graph=1  LEFT DOUBLE ANGLE BRACKET
    U+00300C gc=Ps columns=2 print=1 graph=1  LEFT CORNER BRACKET
    U+00302B gc=Mn columns=0 print=1 graph=1  IDEOGRAPHIC RISING TONE MARK
    U+003030 gc=Pd columns=2 print=1 graph=1  WAVY DASH
    U+003037 gc=So columns=2 print=1 graph=1  IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL
    U+003041 gc=Lo columns=2 print=1 graph=1  HIRAGANA LETTER SMALL A
    U+00E000 gc=Co columns=1 print=1 graph=1 <unnamed codepoint in blk=Private_Use_Area>
    U+00F8FF gc=Co columns=1 print=1 graph=1 <unnamed codepoint in blk=Private_Use_Area>
    U+00FB1E gc=Mn columns=0 print=1 graph=1  HEBREW POINT JUDEO-SPANISH VARIKA
    U+00FE00 gc=Mn columns=0 print=1 graph=1  VARIATION SELECTOR-1
    U+00FE23 gc=Mn columns=0 print=1 graph=1  COMBINING DOUBLE TILDE RIGHT HALF
    U+00FE58 gc=Pd columns=2 print=1 graph=1  SMALL EM DASH
    U+00FE77 gc=Lo columns=1 print=1 graph=1  ARABIC FATHA MEDIAL FORM
    U+00FEFF gc=Cf columns=0 print=1 graph=1  ZERO WIDTH NO-BREAK SPACE
    U+00FF06 gc=Po columns=2 print=1 graph=1  FULLWIDTH AMPERSAND
    U+00FFFA gc=Cf columns=0 print=1 graph=1  INTERLINEAR ANNOTATION SEPARATOR
    U+00FFFD gc=So columns=1 print=1 graph=1  REPLACEMENT CHARACTER
    U+01B000 gc=Lo columns=2 print=1 graph=1  KATAKANA LETTER ARCHAIC E
    U+01D165 gc=Mc columns=1 print=1 graph=1  MUSICAL SYMBOL COMBINING STEM
    U+01D167 gc=Mn columns=0 print=1 graph=1  MUSICAL SYMBOL COMBINING TREMOLO-1
    U+100002 gc=Co columns=1 print=1 graph=1 <unnamed codepoint in blk=Supplementary_Private_Use_Area-B>
    

    它们中的一些对于它们打印什么,甚至是否打印是非常有条件的。例如,你觉得 U+F8FF 的‹›是什么样的?

    然后您必须决定如何处理制表符和退格键。

    此外,您还必须考虑用于构建 Unicode 扩展字形簇的各种 \p{Grapheme_Extend} 代码点;也就是说,用户可见的字符。并非所有这些都是非间距标记。事实上,有些根本不是标记,而是字母!有些根本不是可打印的字符,但它们改变了它们不可避免地附加到的可打印的\p{Grapheme_Base} 字符;以变​​体选择器为例。

    警告

    这将我们带到了一个非常重要的点,它经常被潜在的 Java 程序员忘记,即使没有完全忘记,通常也被低估了。

    永远、永远、永远记住 Java 字符不是 Unicode 字符! Unicode 字符有两种合理的定义,而 Java 两者都没有。以下是两个合理的定义:

    • 如果一个字符是 programmer-visible 意义上的字符,那么一个字符就是一个 Unicode 代码点。这就是 . 在正则表达式引擎中匹配的内容,例如,无论您使用 Sun 的还是 ICU 的。
    • 如果字符是 用户可见 意义上的字符,那么字符就是 Unicode 扩展字素簇。这是 \X 在(ICU 而非 Sun)正则表达式引擎中匹配的内容。

    Java 所谓的“字符”是实际 Unicode 代码点的可变宽度 UTF-16 表示的低级、打破抽象的 2 字节元素。它既不是抽象代码点,也不是抽象字素。它不是抽象的任何东西。 Java char 违反了抽象的信封。

    是的,一些 Java 类为您提供了codePointAt 接口,您绝对应该在任何可用的地方使用它们。但是在许多方面,这里需要很长时间来解释,Java 从根本上破坏了它的字符抽象——因为它没有字符抽象。

    这使得在 Java 中使用 Unicode 字符和字符串最容易出错,而且通常几乎是不可能的。

    祝你好运。

    【讨论】:

      猜你喜欢
      • 2015-03-15
      • 1970-01-01
      • 2011-03-30
      • 2019-04-15
      • 2010-09-24
      • 2020-07-15
      • 2013-04-13
      • 2014-08-03
      • 1970-01-01
      相关资源
      最近更新 更多