Regex: що таке InCombiningDiacriticalMarks?


86

Наступний код добре відомий для перетворення наголошених символів у звичайний текст:

Normalizer.normalize(text, Normalizer.Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");

Я замінив свій "рукотворний" метод цим, але мені потрібно зрозуміти "регулярний вираз" частини replaceAll

1) Що таке "InCombiningDiacriticalMarks"?
2) Де знаходиться його документація? (і подібні дані?)

Дякую.


Див. Також stackoverflow.com/a/29111105/32453, мабуть, в Unicode більше "комбінуючих знаків", ніж просто діакритичних, просто як примітка.
rogerdpack

Відповіді:


74

\p{InCombiningDiacriticalMarks}є властивістю блоку Unicode. У JDK7 ви зможете написати його, використовуючи двоскладовий запис \p{Block=CombiningDiacriticalMarks}, що може бути зрозумілішим для читача. Це задокументовано тут, в UAX № 44: “База даних символів Unicode” .

Це означає, що кодова точка потрапляє до певного діапазону, блоку, який був призначений для використання для речей з такою назвою. Це поганий підхід, оскільки немає жодної гарантії того, що кодова точка в цьому діапазоні є чи не є якоюсь конкретною річчю, і що кодові точки поза цим блоком по суті не мають однакового символу.

Наприклад, у \p{Latin_1_Supplement}блоці є латинські літери , такі як é, U + 00E9. Однак є речі, які там теж не є латинськими літерами. І звичайно, всюди є також латинські літери.

Блоки майже ніколи не є тим, що ви хочете.

У цьому випадку я підозрюю, що, можливо, ви захочете скористатися власністю \p{Mn}, вона ж \p{Nonspacing_Mark}. Усі кодові точки в блоці Combining_Diacriticals є такого роду. Є також (станом на Unicode 6.0.0) 1087 Nonspacing_Marks, яких немає в цьому блоці.

Це майже те ж саме , як перевірка \p{Bidi_Class=Nonspacing_Mark}, але не зовсім, тому що група також включає в себе огороджувальні знаки, \p{Me}. Якщо ви хочете обидва, ви можете сказати, [\p{Mn}\p{Me}]чи використовуєте типовий механізм регулярних виразів Java, оскільки він надає доступ лише до властивості General_Category.

Вам потрібно було б використовувати JNI, щоб потрапити до бібліотеки регулярних виразів ICU C ++ так, як це робить Google, щоб отримати доступ до чогось подібного \p{BC=NSM}, оскільки зараз лише ICU та Perl дають доступ до всіх властивостей Unicode. Звичайна бібліотека регулярних виразів Java підтримує лише кілька стандартних властивостей Unicode. У JDK7, однак, буде підтримка властивостей Unicode Script, що майже нескінченно краще, ніж властивість Block. Таким чином, ви можете в JDK7 писати \p{Script=Latin}або \p{SC=Latin}, або в ярлику \p{Latin}, отримувати будь-який символ з латинського алфавіту. Це призводить до дуже часто необхідних [\p{Latin}\p{Common}\p{Inherited}].

Майте на увазі, що це не видалить те, що ви можете вважати знаком "акценту" з усіх символів! Є багато, для кого це не буде робити. Наприклад, ви не можете перетворити Đ у D або ø в o таким чином. Для цього вам потрібно зменшити кодові точки до тих, які відповідають тій самій первинній силі сортування в таблиці зіставлення Unicode.

Інше місце, де \p{Mn}справа не вдається, - це, звичайно, додавання знаків, як \p{Me}, очевидно, але є також \p{Diacritic}символи, які не є знаками. На жаль, вам потрібна повна майнова підтримка для цього, що означає JNI для ICU або Perl. Боюсь, у Java багато проблем із підтримкою Unicode.

О, почекай, я бачу, ти португалець. Тоді у вас не повинно виникнути проблем, якщо ви маєте справу лише з португальським текстом.

Однак я не дуже хочу видаляти акценти, я впевнений, але швидше хочеш мати можливість відповідати речам "без наголосу", чи не так? Якщо так, то ви можете зробити це за допомогою класу сортувальника ICU4J (ICU для Java) . Якщо порівнювати за основною силою, знаки акценту не враховуються. Я роблю це постійно, оскільки часто обробляю текст іспанською мовою. У мене є приклад, як це зробити для іспанців, які сидять тут десь, якщо вам це потрібно.


Отже, я повинен припустити, що метод, наведений в Інтернеті (і навіть тут, у SO), не є рекомендованим для слова "DeAccent". Я зробив прямий варіант лише для португальської, але побачив цей дивний підхід (і, як ви сказали, це працює для моєї мети, але так зробив мій останній метод!). Тож, чи є кращий «добре впроваджений» підхід, який охоплюватиме більшість сценаріїв? Приклад буде дуже приємним. Дякую за ваш час.
marcolopes

1
@Marcolopes: Я залишаю цілі дані цілими і використовую алгоритм збору Unicode для порівняння первинної сили. Таким чином він просто порівнює літери, але ігнорує як регістр, так і знаки наголосу. Це також дозволяє речам, які повинні бути однією і тією ж літерою, бути тією самою буквою, що видалення акцентів є лише блідим і незадовільним наближенням. Плюс, чистіше не записувати дані, якщо ви можете працювати з ними так, щоб робити те, що ви хочете, але не вимагає цього.
christ

Досить гарна відповідь, хоча одне питання, чи можу я використовувати Normalizer у Java та використовувати InCombiningDiacriticalMarks, але виключити деякі символи, такі як ü, з перетворення на u?
AlexCon

6
так, я цілком це все зрозумів
Dónal

4

Мені знадобився час, але я їх усіх виловив:

Ось регулярний вираз, який повинен включати всі символи залго, включаючи ті, які обійшли в "нормальному" діапазоні.

([\u0300–\u036F\u1AB0–\u1AFF\u1DC0–\u1DFF\u20D0–\u20FF\uFE20–\uFE2F\u0483-\u0486\u05C7\u0610-\u061A\u0656-\u065F\u0670\u06D6-\u06ED\u0711\u0730-\u073F\u0743-\u074A\u0F18-\u0F19\u0F35\u0F37\u0F72-\u0F73\u0F7A-\u0F81\u0F84\u0e00-\u0eff\uFC5E-\uFC62])

Сподіваюся, це заощадить ваш час.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.