Regex: o que é o InCombiningDiacriticalMarks?

O código a seguir é muito bem conhecido para converter caracteres acentuados em texto simples:

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

Eu substituí meu método “hand made” por este, mas eu preciso entender a parte “regex” do replaceAll

1) O que é “InCombiningDiacriticalMarks”?
2) Onde está a documentação disso? (e similares?)

Obrigado.

\p{InCombiningDiacriticalMarks} é uma propriedade de bloco Unicode. No JDK7, você poderá escrevê-lo usando a notação de duas partes \p{Block=CombiningDiacriticalMarks} , que pode ser mais clara para o leitor. Está documentado aqui na UAX # 44: “The Unicode Character Database” .

O que isso significa é que o ponto de código está dentro de um determinado intervalo, um bloco, que foi alocado para usar as coisas com esse nome. Essa é uma abordagem ruim, porque não há garantia de que o ponto de código nesse intervalo seja ou não alguma coisa em particular, nem que os pontos de código fora desse bloco não sejam essencialmente do mesmo caractere.

Por exemplo, há letras latinas no bloco \p{Latin_1_Supplement} , como é, U + 00E9. No entanto, há coisas que também não são letras latinas. E, claro, há também letras latinas em todo o lugar.

Os blocos quase nunca são o que você quer.

Nesse caso, suspeito que você queira usar a propriedade \p{Mn} , também conhecida como \p{Nonspacing_Mark} . Todos os pontos de código no bloco Combining_Diacriticals são desse tipo. Há também (a partir do Unicode 6.0.0) 1087 Nonspacing_Marks que não estão nesse bloco.

Isso é quase o mesmo que verificar para \p{Bidi_Class=Nonspacing_Mark} , mas não completamente, porque esse grupo também inclui as marcas de fechamento, \p{Me} . Se você quer ambos, você poderia dizer [\p{Mn}\p{Me}] se você estiver usando um mecanismo regex Java padrão, já que ele apenas dá access à propriedade General_Category.

Você teria que usar o JNI para acessar a biblioteca de regex ICU C ++ da maneira que o Google faz para acessar algo como \p{BC=NSM} , porque agora apenas ICU e Perl dão access a todas as propriedades Unicode. A biblioteca normal de regex Java suporta apenas algumas propriedades Unicode padrão. No JDK7, porém, haverá suporte para a propriedade Unicode Script, que é praticamente infinitamente preferível à propriedade Block. Assim, no JDK7, você pode escrever \p{Script=Latin} ou \p{SC=Latin} , ou o atalho \p{Latin} , para obter qualquer caractere do alfabeto latino. Isso leva ao comumente necessário [\p{Latin}\p{Common}\p{Inherited}] .

Esteja ciente de que isso não removerá o que você pode imaginar como marcas de “sotaque” de todos os personagens! Há muitos que não farão isso. Por exemplo, você não pode converter Đ para D ou ø para o assim. Para isso, você precisa reduzir os pontos de código para aqueles que correspondam à mesma força de agrupamento primária na Tabela de Agrupamento Unicode.

Outro lugar onde a coisa de \p{Mn} falha é claro, colocando marcas como \p{Me} , obviamente, mas também há caracteres \p{Diacritic} que não são marcas. Infelizmente, você precisa de suporte integral à propriedade para isso, o que significa JNI para ICU ou Perl. Java tem um monte de problemas com suporte a Unicode, estou com medo.

Oh espere, vejo que você é português. Você não deve ter nenhum problema se estiver lidando apenas com o texto em português.

No entanto, você realmente não quer remover os acentos, eu aposto, mas sim você quer ser capaz de combinar as coisas “insensível ao sotaque”, certo? Em caso afirmativo, você pode fazer isso usando a class collator ICU4J (ICU for Java) . Se você comparar com a força primária, as marcas de acentuação não serão contadas. Eu faço isso o tempo todo, porque geralmente processo textos em espanhol. Eu tenho um exemplo de como fazer isso para o espanhol sentado aqui em algum lugar, se você precisar.

Demorou um pouco, mas eu pesquei tudo:

Aqui está a regex que deve include todos os caracteres zalgo, incluindo os omitidos no intervalo “normal”.

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

Espero que isso economize algum tempo.