Existe uma maneira melhor de se livrar dos acentos e tornar essas letras regulares, além de usar o String.replaceAll()
método e substituir as letras uma a uma? Exemplo:
Entrada: orčpžsíáýd
Resultado: orcpzsiayd
Não é necessário incluir todas as letras com acentos, como o alfabeto russo ou o chinês.
java
string
diacritics
Martin
fonte
fonte
string.replaceAll("\\p{M}", "")
. Veja regular-expressions.info/unicode.html para mais informações.A partir de 2011, você pode usar o Apache Commons StringUtils.stripAccents (input) (desde 3.0):
Nota:
A resposta aceita (Erick Robertson) não funciona para Ø ou Ł. O Apache Commons 3.5 também não funciona para Ø, mas funciona para Ł. Depois de ler o artigo da Wikipedia sobre Ø , não tenho certeza se deve ser substituído por "O": é uma letra separada em norueguês e dinamarquês, alfabetizada após "z". É um bom exemplo das limitações da abordagem "tira sotaques".
fonte
A solução do @ virgo47 é muito rápida, mas aproximada. A resposta aceita usa o Normalizador e uma expressão regular. Gostaria de saber qual parte do tempo foi gasta pelo Normalizer versus a expressão regular, pois a remoção de todos os caracteres não ASCII pode ser feita sem uma expressão regular:
Pequenas acelerações adicionais podem ser obtidas escrevendo um char [] e não chamandoCharCharrray (), embora eu não tenha certeza de que a diminuição na clareza do código o mereça:
Essa variação tem a vantagem da correção de quem usa o Normalizer e da velocidade de quem usa uma tabela. Na minha máquina, essa é cerca de 4x mais rápida que a resposta aceita e 6,6x a 7x mais lenta que a @ virgo47 (a resposta aceita é 26x mais lenta que a @ virgo47 na minha máquina).
fonte
out
deve ser redimensionado para corresponder ao número de caracteres válidosj
antes de ser usado para construir o objeto de sequência.flattenToAscii
cria o resultado "aa .." onde os pontos representam \ u0000. Isso não é bom. A primeira pergunta é - como representar caracteres "anormais"? Digamos que será?, Ou podemos deixar o caractere NULL lá, mas, em qualquer caso, temos que preservar a posição correta deles (assim como a solução regex). Para isso, o if no loop deve ser algo como:if (c <= '\u007F') out[j++] = c; else if (Character.isLetter(c)) out[j++] = '?';
Ele diminuirá a velocidade um pouco, mas deve estar correto em primeiro lugar. ;-)isLetter
) não seja a correta, mas não achei melhor. Como não sou especialista em Unicode, não sei como identificar melhor a classe do caractere único que substitui o caractere original. As letras funcionam bem para a maioria dos aplicativos / usos.EDIT: Se você não está preso ao Java <6 e a velocidade não é crítica e / ou a tabela de conversão é muito limitadora, use a resposta de David. O objetivo é usar
Normalizer
(introduzido no Java 6) em vez da tabela de conversão dentro do loop.Embora essa não seja uma solução "perfeita", ela funciona bem quando você conhece o intervalo (no nosso caso, Latin1,2), trabalhou antes do Java 6 (embora não seja um problema real) e é muito mais rápido que a versão mais sugerida (pode ou pode não seja um problema):
Testes no meu HW com JDK de 32 bits mostram que isso realiza a conversão de àèéľšťč89FDČ para aeelstc89FDC 1 milhão de vezes em ~ 100ms, enquanto o modo Normalizador o torna em 3,7s (37x mais lento). Caso suas necessidades estejam relacionadas ao desempenho e você saiba o intervalo de entrada, isso pode ser para você.
Aproveitar :-)
fonte
trabalhou para mim. A saída do snippet acima fornece "aee", que é o que eu queria, mas
não fez nenhuma substituição.
fonte
Dependendo do idioma, esses podem não ser considerados acentos (que alteram o som da letra), mas marcas diacríticas
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_containing_diacritics
"Bósnio e croata têm os símbolos č, ć, đ, š e ž, que são considerados letras separadas e são listados como tal em dicionários e outros contextos nos quais as palavras são listadas de acordo com a ordem alfabética."
Removê-los pode estar inerentemente alterando o significado da palavra ou mudando as letras para letras completamente diferentes.
fonte
Eu enfrentei o mesmo problema relacionado à verificação de igualdade de Strings. Uma das strings de comparação possui o código de caracteres ASCII 128-255 .
Use o código abaixo para diferentes espaços e seus códigos de bytes:
wiki for List_of_Unicode_characters
Transl Transliterações ASCII da cadeia Unicode para Java.
unidecode
➩ usando
Guava
: Google CoreLibraries for Java
.Para codificação de URL para o espaço, use Guava laibrary.
➩ Para superar esse problema usado
String.replaceAll()
com algunsRegularExpression
.➩ Usando java.text.Normalizer.Form . Essa enumeração fornece constantes dos quatro formulários de normalização Unicode descritos no Anexo Padrão 15 do Unicode - Formulários de Normalização Unicode e dois métodos para acessá-los.
Testando String e saídas em diferentes abordagens, como id Unidecode, Normalizer, StringUtils .
Usando Unidecode é o
best choice
, Meu código final mostrado abaixo.fonte
Eu sugiro Junidecode . Ele manipulará não apenas 'Ł' e 'Ø', mas também funcionará bem para transcrever de outros alfabetos, como o chinês, para o alfabeto latino.
fonte
A solução @David Conrad é a mais rápida que tentei usar o Normalizer, mas tem um bug. Ele basicamente retira caracteres que não são acentuados, por exemplo, caracteres chineses e outras letras como æ, são todos removidos. Os caracteres que queremos extrair são marcas sem espaçamento, caracteres que não ocupam largura extra na sequência final. Esses caracteres de largura zero basicamente acabam combinados em algum outro caractere. Se você pode vê-los isolados como um personagem, por exemplo, `` meu palpite é que é combinado com o caractere de espaço.
fonte
Uma das melhores maneiras de usar o regex e o Normalizer se você não tiver uma biblioteca é:
Isso é mais eficiente que replaceAll ("[^ \ p {ASCII}]", "")) e se você não precisar de sinais diacríticos (como no seu exemplo).
Caso contrário, você precisará usar o padrão p {ASCII}.
Saudações.
fonte
Eu acho que a melhor solução é converter cada caractere para HEX e substituí-lo por outro HEX. É porque existem 2 digitações Unicode:
Por exemplo, "Ồ" escrito por Composite Unicode é diferente de "Ồ" escrito por Precomposed Unicode. Você pode copiar meus caracteres de amostra e convertê-los para ver a diferença.
Desenvolvi esse recurso para alguns bancos para converter as informações antes de enviá-las ao banco central (geralmente não suportam Unicode) e enfrentei esse problema quando os usuários finais usam várias digitações Unicode para inserir os dados. Então eu acho que converter para HEX e substituí-lo é a maneira mais confiável.
fonte
Caso alguém esteja lutando para fazer isso no kotlin, esse código funcionará como um encanto. Para evitar inconsistências, também uso .toUpperCase e Trim (). então eu lancei esta função:
}
Para usá-los, transmita o código da seguinte maneira:
fonte