web-dev-qa-db-fra.com

Regex: qu'est-ce que InCombiningDiacriticalMarks?

Le code suivant est très connu pour convertir des 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 j'ai besoin de comprendre la partie "regex" de replaceAll

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

Merci.

79
marcolopes

\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: "The Unicode Character Database" .

Cela signifie que le point de code se situe dans une plage particulière, un bloc, qui a été alloué pour être utilisé pour les choses de ce nom. Il s'agit d'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 en dehors 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 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}, alias. \p{Nonspacing_Mark}. Tous les points de code du bloc Combining_Diacriticals sont de ce type. Il y a aussi (à partir d'Unicode 6.0.0) 1087 Nonspacing_Marks qui sont pas dans ce bloc.

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

Vous devez utiliser JNI pour accéder à la bibliothèque ICU C++ regex comme Google le fait pour accéder à quelque chose comme \p{BC=NSM}, car pour l'instant seuls ICU et Perl donnent accès aux tous propriétés Unicode. La bibliothèque normale Java regex ne prend en charge que quelques propriétés standard Unicode. Dans JDK7, bien qu'il y ait le sera soit pris en charge la propriété Unicode Script, qui est à peu près infinie préférable à la propriété Block. Ainsi, dans JDK7, vous pouvez é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 très couramment nécessaire [\p{Latin}\p{Common}\p{Inherited}].

Sachez que cela ne supprimera pas ce que vous pourriez considérer comme des marques "d'accent" de tous les personnages! Il y en a beaucoup pour qui il ne le fera pas. Par exemple, vous ne pouvez pas convertir Đ en [~ # ~] d [~ # ~] ou ø à o de cette façon. Pour cela, vous devez réduire les points de code à ceux qui correspondent à la même force de classement primaire dans la table de classement Unicode.

Un autre endroit où le \p{Mn} ce qui échoue est bien sûr de mettre des marques comme \p{Me}, bien sûr, mais il y a aussi \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 soit ICU ou Perl. Java a beaucoup de problèmes avec la prise en charge Unicode, je suis peur.

Oh attends, je vois que tu es portugais. Vous ne devriez donc avoir aucun problème si vous ne vous occupez que du texte portugais.

Cependant, vous ne voulez pas vraiment supprimer les accents, je parie, mais plutôt vous voulez être en mesure de faire correspondre les choses "sans accentuation", 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'accent ne compteront pas. Je le fais tout le temps car 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.

68
tchrist

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

Voici regex 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.

4
Matas Vaitkevicius