Regex: qu'est-ce que InCombiningDiacriticalMarks?

86

Le code suivant est très connu pour convertir les caractères accentués en texte brut:

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

J'ai remplacé ma méthode "faite à la main" par celle-ci, mais je dois comprendre la partie "regex" de replaceAll

1) Qu'est-ce que "InCombiningDiacriticalMarks"?
2) Où en est la documentation? (et similaires?)

Merci.

marcolopes
la source
Voir aussi stackoverflow.com/a/29111105/32453 apparemment, il y a plus de "marques de combinaison" en Unicode que de simples signes diacritiques, juste comme une note.
rogerdpack

Réponses:

74

\p{InCombiningDiacriticalMarks}est une propriété de bloc Unicode. Dans JDK7, vous pourrez l'écrire en utilisant la notation en deux parties \p{Block=CombiningDiacriticalMarks}, ce qui peut être plus clair pour le lecteur. Il est documenté ici dans UAX # 44: «La base de données de caractères Unicode» .

Cela signifie que le point de code se trouve dans une plage particulière, un bloc, qui a été alloué pour être utilisé pour les choses portant ce nom. C'est une mauvaise approche, car il n'y a aucune garantie que le point de code dans cette plage est ou n'est pas une chose particulière, ni que les points de code à l'extérieur de ce bloc ne sont pas essentiellement du même caractère.

Par exemple, il y a des lettres latines dans le \p{Latin_1_Supplement}bloc, comme é, U + 00E9. Cependant, il y a aussi des choses qui ne sont pas des lettres latines. Et bien sûr, il y a aussi des lettres latines partout.

Les blocs ne sont presque jamais ce que vous voulez.

Dans ce cas, je soupçonne que vous souhaiterez peut-être utiliser la propriété \p{Mn}, aka \p{Nonspacing_Mark}. Tous les points de code du bloc Combining_Diacriticals sont de ce type. Il existe également (à partir d'Unicode 6.0.0) 1087 Nonspacing_Marks qui ne sont pas dans ce bloc.

C'est presque le même que pour vérifier \p{Bidi_Class=Nonspacing_Mark}, mais pas tout à fait, parce que ce groupe comprend aussi les marques de Enserrage \p{Me}. Si vous voulez les deux, vous pouvez dire [\p{Mn}\p{Me}]si vous utilisez un moteur d'expression régulière Java par défaut, car il ne donne accès qu'à la propriété General_Category.

Vous devrez utiliser JNI pour accéder à la bibliothèque de regex ICU C ++ comme Google le fait pour accéder à quelque chose comme \p{BC=NSM}, car pour le moment, seuls ICU et Perl donnent accès à toutes les propriétés Unicode. La bibliothèque standard Java regex ne prend en charge que quelques propriétés Unicode standard. Dans JDK7 cependant, il y aura un support pour la propriété Unicode Script, qui est à peu près infiniment préférable à la propriété Block. Ainsi, vous pouvez dans JDK7 écrire \p{Script=Latin}ou \p{SC=Latin}, ou le raccourci \p{Latin}, pour accéder à n'importe quel caractère du script latin. Cela conduit à la nécessité très courante [\p{Latin}\p{Common}\p{Inherited}].

Sachez que cela ne supprimera pas ce que vous pourriez considérer comme des marques «accentuées» de tous les caractères! Il y en a beaucoup pour lesquels il ne le fera pas. Par exemple, vous ne pouvez pas convertir Đ en D ou ø en o de cette façon. Pour cela, vous devez réduire les points de code à ceux qui correspondent à la même force de classement principal dans la table de classement Unicode.

Un autre endroit où la \p{Mn}chose échoue est bien sûr de renfermer des marques comme \p{Me}, évidemment, mais aussi il y a des \p{Diacritic}caractères qui ne sont pas des marques. Malheureusement, vous avez besoin d'une prise en charge complète des propriétés pour cela, ce qui signifie que JNI est soit ICU, soit Perl. Java a beaucoup de problèmes avec le support Unicode, j'en ai peur.

Oh attendez, je vois que vous êtes portugais. Vous ne devriez avoir aucun problème si vous ne traitez que du texte portugais.

Cependant, vous ne voulez pas vraiment supprimer les accents, je parie, mais vous voulez plutôt pouvoir faire correspondre les choses «sans accent», non? Si tel est le cas, vous pouvez le faire à l'aide de la classe d'assemblage ICU4J (ICU pour Java) . Si vous comparez à la force principale, les marques d'accentuation ne compteront pas. Je fais cela tout le temps parce que je traite souvent du texte espagnol. J'ai un exemple de la façon de faire cela pour l'espagnol assis quelque part ici si vous en avez besoin.

tchrist
la source
Donc, je dois supposer que la méthode donnée dans tout le web (et même ici à SO) n'est pas celle recommandée pour "DeAccent" un mot. J'ai fait une simple juste pour le portugais, mais j'ai vu cette approche étrange (et comme vous l'avez dit, cela fonctionne pour mon but, mais c'est ce que ma dernière méthode a fait!). Alors, y a-t-il une meilleure approche «bien mise en œuvre» qui couvrira la plupart des scénarios? Un exemple serait très bien. Merci pour votre temps.
marcolopes
1
@Marcolopes: J'ai laissé les données intactes et j'ai utilisé l'algorithme de classement Unicode pour faire des comparaisons de force primaire. De cette façon, il compare simplement les lettres, mais ignore les marques de casse et d'accentuation. Cela permet également aux choses qui devraient être la même lettre d' être la même lettre, dont la suppression des accents n'est qu'une pâle approximation et peu satisfaisante. De plus, il est plus propre de ne pas zapper les données si vous pouvez les utiliser d'une manière qui fait ce que vous voulez mais ne l'exige pas.
tchrist
Assez bonne réponse, une question cependant, puis-je utiliser Normalizer en java et utiliser InCombiningDiacriticalMarks mais exclure certains caractères tels que ü de la conversion en u?
AlexCon
6
ouais, j'ai totalement compris tout ça
Dónal
4

Cela m'a pris du temps, mais je les ai tous pêchés:

Voici l'expression régulière qui devrait inclure tous les caractères zalgo, y compris ceux contournés dans la plage «normale».

([\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])

J'espère que cela vous fera gagner du temps.

Matas Vaitkevicius
la source