Фильтрация символов, отсутствующих в шрифте пользователя в Java
Я хочу создать довольно простую таблицу с использованием Java (в качестве упражнения), чтобы проверить наличие допустимой печатаемой кодовой точки Unicode в шрифте конечного пользователя. Поскольку некоторые шрифты не могут печатать действительные кодовые точки, я должен знать, какие печатаемые кодовые точки, тем не менее, отсутствует у шрифта пользователя, и поэтому не может печатать.
Например, если шрифт поддерживает только латинские символы, я не могу печатать греческие символы, используя его, не говоря уже о японских символах. Unicode говорит, что они все для печати, но шрифт пользователя может быть недостаточно хорошим.
После небольшого исследования я смог напечатать большинство символов в Eclipse (с помощью настройки Encoding). Однако у меня все еще есть несколько неизвестных / непечатаемых символов в моем выводе, в этом, когда я смотрю на вывод, я вижу все эти пустые прямоугольники для некоторых из моих печатных символов.
Я пытался их отфильтровать, но не могу найти способ сделать это. К вашему сведению, я просто устанавливаю значение символа на 50, 100 или 1000, а затем увеличиваю его с помощью for
оттуда, чтобы проверить, какие символы я могу или не могу (или не должен?) печатать.
Кто-нибудь может дать мне несколько советов о том, с чего начать?
2 ответа
Ваша задача на самом деле немного сложнее, чем кодирование, потому что шрифт, из которого вы пытаетесь напечатать, имеет большое значение в выводе. Т.е. не все шрифты поддерживают одинаковый набор символов. На самом деле, поддержка диапазонов символов сильно отличается от шрифта к шрифту.
Тем не менее, ваша проблема теперь становится: Как я могу определить, поддерживает ли определенный шрифт данный символ? И этот вопрос был задан и получен ответ... Смотрите здесь документ о Java функции canDisplay, которая является членом класса Font.
Непонятно, что вы на самом деле и именно здесь имеете в виду. Если вы планируете играть по номерам, то в Приложении C Технического стандарта Unicode № 18 " Регулярные выражения Unicode" дается конкретное предложение о том, что "печатная" кодовая точка должна быть определена как любая кодовая точка, имеющая 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}]
Или как Java 1.7 Pattern
класс документирует их, если вы скомпилируете шаблон с включенным новым для 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 ‹› для вас?
Затем вы должны решить, как обрабатывать вкладки и возврат.
Плюс вам придется рассмотреть различные\p{Grapheme_Extend}
кодовые точки, используемые для создания кластера расширенных графем Unicode; то есть видимый пользователю символ. Не все это непроходные отметки. На самом деле, это не знаки, а буквы! Некоторые из них вообще не являются печатными символами, и все же они меняют печатные символы\p{Grapheme_Base}
характер, к которому они неизбежно привязаны; Рассмотрим в качестве одного из примеров селекторы вариаций.
Предупреждение
Это подводит нас к критически важному моменту, который слишком часто забывают потенциальные программисты на Java, и даже если он не полностью забыт, его обычно недооценивают.
Всегда, всегда, всегда помните, чтосимволы Java не являются символами Юникода! Есть два разумных определения символа Unicode, и Java не дает ни того, ни другого. Вот два разумных определения:
- Если символ является символом в понимании программиста, то символ является точкой кода Unicode. Это то, что
.
совпадения в движке регулярных выражений, например, независимо от того, используете ли вы Sun или ICU. - Если символ является символом в видимом для пользователя смысле, тогда символ представляет собой кластер расширенных графем Unicode. Это то, что
\X
совпадения в (регулярном выражении (не ICU)) движке регулярных выражений.
Так называемый "символ" Java - это низкоуровневый двухбайтовый элемент разбиения на абстрактные символы представления UTF-16 переменной ширины действительной кодовой точки Unicode. Это не абстрактная кодовая точка и не абстрактная графема. Это не абстрактное ничто. Java char
является нарушением оболочки абстракции.
Да, некоторые классы Java дают вам codePointAt
интерфейс, и вы должны абсолютно использовать те, где они доступны. Но во многих отношениях, которые здесь объясняются слишком долго, Java в корне сломана в своей абстракции символов - потому что у нее ее нет.
Это делает работу с символами и строками Юникода в лучшем случае подверженной ошибкам в Java, а часто почти невозможной.
Удачи.