Поддержка 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 все равно будет рассматривать их как два символа как элементы строки).

Две ссылки:

Кодировка Unicode 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 внутри, не имеют этих ограничений. Они также никогда не заставляют вас указывать кодовые единицы, которые не идентичны кодовым точкам.

Другие вопросы по тегам