Поддержка Java для не-BMP символов Unicode (т.е. кодовые точки> 0xFFFF) в их библиотеке регулярных выражений?
В настоящее время я использую Java 6 (у меня нет возможности перейти на Java 7), и я пытаюсь использовать пакет java.util.regex для сопоставления с образцом строк, содержащих символы Unicode.
Я знаю, что java.lang.String поддерживает дополнительные символы (т.е. символы с кодовыми точками> 0xFFFF) (начиная с Java 5), но я не вижу простого способа сопоставления с этими символами. java.util.regex.Pattern по-прежнему позволяет отображать только шестнадцатеричные числа, используя 4 цифры (например, \uFFFF)
Кто-нибудь знает, если я здесь пропускаю API?
2 ответа
Я никогда не делал сопоставления с дополнительными символами, но думаю, что это так же просто, как кодировать их (в шаблонах и строках), как два 16-битных числа (суррогатная пара UTF-16) \unnnn\ummmm . java.util.regex
Должен быть достаточно умен, чтобы интерпретировать эти два числа (символы Java) как один символ в шаблонах и строках (хотя Java все равно будет рассматривать их как два символа как элементы строки).
Две ссылки:
http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
С последней ссылки (ссылка на Java 5):
Пакет java.util.regex был обновлен, так что и строки шаблона, и строки назначения могут содержать дополнительные символы, которые будут обрабатываться как полные единицы.
Также обратите внимание, что если вы используете UTF8 в качестве кодировки (для исходных файлов), вы также можете написать их напрямую (см. Раздел "Представление дополнительных символов в исходных файлах" в последней ссылке).
Например:
String pat1 = ".*\uD840\uDC00{2}.*";
String s1 = "HI \uD840\uDC00\uD840\uDC00 BYE";
System.out.println(s1.matches(pat1) + " len=" + s1.length());
String pat2 = ".*\u0040\u0041{2}.*";
String s2 = "HI \u0040\u0041\u0040\u0041 BYE";
System.out.println(s2.matches(pat2) + " len=" + s2.length());
Это, скомпилированный с Java 6, печатает
true len=11
false len=11
что согласуется с вышесказанным. В первом случае у нас есть одна кодовая точка, представленная в виде пары суррогатных java-символов (два 16-битных символа, один дополнительный символ Unicode) и {2}
квантификатор применяется к паре (= кодовая точка). Во втором у нас есть два разных символа BMP, квантификатор применяется к последнему - следовательно, нет совпадения.
Однако обратите внимание, что длина строки одинакова (поскольку Java измеряет длину строки, считая символы Java, а не кодовые точки Unicode).
Самое простое решение - использовать кодировку UTF-8 для вашего исходного кода. Затем просто вставьте персонажей напрямую. Вы никогда не должны когда-либо указывать отдельные блоки кода в любой программе.
Тем не менее, существует проблема с классами символов, потому что внутренняя кодировка UTF-16 в Java испортила их. Вы не можете использовать полный Unicode до JDK7, где даже тогда вам придется указывать логические кодовые точки, используя косвенные \x{HHHHH}
нотации. Вы по-прежнему не сможете иметь буквальный код в charclass, но вы можете избежать этого с помощью \x{H..H}
,
Несовершенный, но он намного лучше, чем был. UTF-16 - это всегда компромисс. Системы, которые используют UTF-8 или UTF-32 внутри, не имеют этих ограничений. Они также никогда не заставляют вас указывать кодовые единицы, которые не идентичны кодовым точкам.