Como faço para remover diacríticos (acentos) de uma string no .net?

Eu estou tentando converter algumas cordas que estão em francês canadense e, basicamente, eu gostaria de ser capaz de tirar o acento francês nas letras, mantendo a letra. (Por exemplo, converter é para e , então crème brûlée se tornaria creme brulee )

Qual é o melhor método para alcançar isso?

Eu não usei esse método, mas Michael Kaplan descreve um método para fazer isso em seu post (com um título confuso) que fala sobre decapagem de diacríticos: Stripping é um trabalho interessante (também conhecido como Sobre o significado de sem sentido, também conhecido como All Mn characters). são não-espaçadores, mas alguns são mais espaçados do que outros)

 static string RemoveDiacritics(string text) { var normalizedString = text.Normalize(NormalizationForm.FormD); var stringBuilder = new StringBuilder(); foreach (var c in normalizedString) { var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); if (unicodeCategory != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(c); } } return stringBuilder.ToString().Normalize(NormalizationForm.FormC); } 

Note que este é um followup para o seu post anterior: decapitação diacríticos ….

A abordagem usa String.Normalize para dividir a string de input em glifos constituintes (basicamente separando os caracteres “base” dos diacríticos) e, em seguida, verifica o resultado e retém apenas os caracteres base. É um pouco complicado, mas na verdade você está olhando para um problema complicado.

É claro que, se você está se limitando ao francês, você provavelmente poderia usar a abordagem simples baseada em tabela em Como remover acentos e til em um C ++ std :: string , como recomendado por @David Dibben.

isso fez o truque para mim …

 string accentedStr; byte[] tempBytes; tempBytes = System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(accentedStr); string asciiStr = System.Text.Encoding.UTF8.GetString(tempBytes); 

rápido e curto!

Caso alguém esteja interessado, procurei algo parecido e terminei de escrever o seguinte:

  public static string NormalizeStringForUrl(string name) { String normalizedString = name.Normalize(NormalizationForm.FormD); StringBuilder stringBuilder = new StringBuilder(); foreach (char c in normalizedString) { switch (CharUnicodeInfo.GetUnicodeCategory(c)) { case UnicodeCategory.LowercaseLetter: case UnicodeCategory.UppercaseLetter: case UnicodeCategory.DecimalDigitNumber: stringBuilder.Append(c); break; case UnicodeCategory.SpaceSeparator: case UnicodeCategory.ConnectorPunctuation: case UnicodeCategory.DashPunctuation: stringBuilder.Append('_'); break; } } string result = stringBuilder.ToString(); return String.Join("_", result.Split(new char[] { '_' } , StringSplitOptions.RemoveEmptyEntries)); // remove duplicate underscolors } 

Caso alguém esteja interessado, aqui está o equivalente a java:

 import java.text.Normalizer; public class MyClass { public static String removeDiacritics(String input) { String nrml = Normalizer.normalize(input, Normalizer.Form.NFD); StringBuilder stripped = new StringBuilder(); for (int i=0;i 

Eu geralmente uso um método de extensão baseado em outra versão que encontrei aqui (veja Substituindo caracteres em C # (ascii) ) Uma explicação rápida:

  • Normalizar para formar D divide caractes como è para um e e um não espaçamento `
  • A partir disso, os caracteres que se aproximam são removidos
  • O resultado é normalizado de volta para o formato C (não tenho certeza se isso é necessário)

Código:

 using System.Linq; using System.Text; using System.Globalization; // namespace here public static class Utility { public static string RemoveDiacritics(this string str) { if (null == str) return null; var chars = from c in str.Normalize(NormalizationForm.FormD).ToCharArray() let uc = CharUnicodeInfo.GetUnicodeCategory(c) where uc != UnicodeCategory.NonSpacingMark select c; var cleanStr = new string(chars.ToArray()).Normalize(NormalizationForm.FormC); return cleanStr; } // or, alternatively public static string RemoveDiacritics2(this string str) { if (null == str) return null; var chars = str .Normalize(NormalizationForm.FormD) .ToCharArray() .Where(c=> CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) .ToArray(); return new string(chars).Normalize(NormalizationForm.FormC); } } 

Eu precisava de algo que convertesse todos os principais caracteres unicode e a resposta votada convert_accented_characters($str) fora, então criei uma versão do convert_accented_characters($str) do CodeIgniter em C # que é facilmente personalizável:

 using System; using System.Text; using System.Collections.Generic; public static class Strings { static Dictionary foreign_characters = new Dictionary { { "äæǽ", "ae" }, { "öœ", "oe" }, { "ü", "ue" }, { "Ä", "Ae" }, { "Ü", "Ue" }, { "Ö", "Oe" }, { "ÀÁÂÃÄÅǺĀĂĄǍΑΆẢẠẦẪẨẬẰẮẴẲẶА", "A" }, { "àáâãåǻāăąǎªαάảạầấẫẩậằắẵẳặа", "a" }, { "Б", "B" }, { "б", "b" }, { "ÇĆĈĊČ", "C" }, { "çćĉċč", "c" }, { "Д", "D" }, { "д", "d" }, { "ÐĎĐΔ", "Dj" }, { "ðďđδ", "dj" }, { "ÈÉÊËĒĔĖĘĚΕΈẼẺẸỀẾỄỂỆЕЭ", "E" }, { "èéêëēĕėęěέεẽẻẹềếễểệеэ", "e" }, { "Ф", "F" }, { "ф", "f" }, { "ĜĞĠĢΓГҐ", "G" }, { "ĝğġģγгґ", "g" }, { "ĤĦ", "H" }, { "ĥħ", "h" }, { "ÌÍÎÏĨĪĬǏĮİΗΉΊΙΪỈỊИЫ", "I" }, { "ìíîïĩīĭǐįıηήίιϊỉịиыї", "i" }, { "Ĵ", "J" }, { "ĵ", "j" }, { "ĶΚК", "K" }, { "ķκк", "k" }, { "ĹĻĽĿŁΛЛ", "L" }, { "ĺļľŀłλл", "l" }, { "М", "M" }, { "м", "m" }, { "ÑŃŅŇΝН", "N" }, { "ñńņňʼnνн", "n" }, { "ÒÓÔÕŌŎǑŐƠØǾΟΌΩΏỎỌỒỐỖỔỘỜỚỠỞỢО", "O" }, { "òóôõōŏǒőơøǿºοόωώỏọồốỗổộờớỡởợо", "o" }, { "П", "P" }, { "п", "p" }, { "ŔŖŘΡР", "R" }, { "ŕŗřρр", "r" }, { "ŚŜŞȘŠΣС", "S" }, { "śŝşșšſσςс", "s" }, { "ȚŢŤŦτТ", "T" }, { "țţťŧт", "t" }, { "ÙÚÛŨŪŬŮŰŲƯǓǕǗǙǛŨỦỤỪỨỮỬỰУ", "U" }, { "ùúûũūŭůűųưǔǖǘǚǜυύϋủụừứữửựу", "u" }, { "ÝŸŶΥΎΫỲỸỶỴЙ", "Y" }, { "ýÿŷỳỹỷỵй", "y" }, { "В", "V" }, { "в", "v" }, { "Ŵ", "W" }, { "ŵ", "w" }, { "ŹŻŽΖЗ", "Z" }, { "źżžζз", "z" }, { "ÆǼ", "AE" }, { "ß", "ss" }, { "IJ", "IJ" }, { "ij", "ij" }, { "Œ", "OE" }, { "ƒ", "f" }, { "ξ", "ks" }, { "π", "p" }, { "β", "v" }, { "μ", "m" }, { "ψ", "ps" }, { "Ё", "Yo" }, { "ё", "yo" }, { "Є", "Ye" }, { "є", "ye" }, { "Ї", "Yi" }, { "Ж", "Zh" }, { "ж", "zh" }, { "Х", "Kh" }, { "х", "kh" }, { "Ц", "Ts" }, { "ц", "ts" }, { "Ч", "Ch" }, { "ч", "ch" }, { "Ш", "Sh" }, { "ш", "sh" }, { "Щ", "Shch" }, { "щ", "shch" }, { "ЪъЬь", "" }, { "Ю", "Yu" }, { "ю", "yu" }, { "Я", "Ya" }, { "я", "ya" }, }; public static char RemoveDiacritics(this char c){ foreach(KeyValuePair entry in foreign_characters) { if(entry.Key.IndexOf (c) != -1) { return entry.Value[0]; } } return c; } public static string RemoveDiacritics(this string s) { //StringBuilder sb = new StringBuilder (); string text = ""; foreach (char c in s) { int len = text.Length; foreach(KeyValuePair entry in foreign_characters) { if(entry.Key.IndexOf (c) != -1) { text += entry.Value; break; } } if (len == text.Length) { text += c; } } return text; } } 

Uso

 // for strings "crème brûlée".RemoveDiacritics (); // creme brulee // for chars "Ã"[0].RemoveDiacritics (); // A 

A CodePage of Greek (ISO) pode fazer isso

As informações sobre essa página de código são em System.Text.Encoding.GetEncodings() . Saiba mais em: https://msdn.microsoft.com/pt-br/library/system.text.encodinginfo.getencoding(v=vs.110).aspx

Grego (ISO) tem página de código 28597 e nome iso-8859-7 .

Vá para o código … \ o /

 string text = "Você está numa situação lamentável"; string textEncode = System.Web.HttpUtility.UrlEncode(text, Encoding.GetEncoding("iso-8859-7")); //result: "Voce+esta+numa+situacao+lamentavel" string textDecode = System.Web.HttpUtility.UrlDecode(textEncode); //result: "Voce esta numa situacao lamentavel" 

Então, escreva esta function …

 public string RemoveAcentuation(string text) { return System.Web.HttpUtility.UrlDecode( System.Web.HttpUtility.UrlEncode( text, Encoding.GetEncoding("iso-8859-7"))); } 

Observe que … Encoding.GetEncoding("iso-8859-7") é equivalente a Encoding.GetEncoding(28597) porque primeiro é o nome e segundo a página de códigos de Codificação.

Isso funciona bem em java.

Basicamente, ele converte todos os caracteres acentuados em suas contrapartes deAccented, seguido por seus diacríticos combinados. Agora você pode usar um regex para remover os diacríticos.

 import java.text.Normalizer; import java.util.regex.Pattern; public String deAccent(String str) { String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD); Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+"); return pattern.matcher(nfdNormalizedString).replaceAll(""); } 

Esta é a versão VB (funciona com GREGO):

Imports System.Text

Imports System.Globalization

 Public Function RemoveDiacritics(ByVal s As String) Dim normalizedString As String Dim stringBuilder As New StringBuilder normalizedString = s.Normalize(NormalizationForm.FormD) Dim i As Integer Dim c As Char For i = 0 To normalizedString.Length - 1 c = normalizedString(i) If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then stringBuilder.Append(c) End If Next Return stringBuilder.ToString() End Function 

É assim que eu substituo os caracteres diacríticos por não-diacríticos em todo o meu programa .NET

C #:

 //Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter 'é' is substituted by an 'e' public string RemoveDiacritics(string s) { string normalizedString = null; StringBuilder stringBuilder = new StringBuilder(); normalizedString = s.Normalize(NormalizationForm.FormD); int i = 0; char c = '\0'; for (i = 0; i < = normalizedString.Length - 1; i++) { c = normalizedString[i]; if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(c); } } return stringBuilder.ToString().ToLower(); } 

VB .NET:

 'Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter "é" is substituted by an "e"' Public Function RemoveDiacritics(ByVal s As String) As String Dim normalizedString As String Dim stringBuilder As New StringBuilder normalizedString = s.Normalize(NormalizationForm.FormD) Dim i As Integer Dim c As Char For i = 0 To normalizedString.Length - 1 c = normalizedString(i) If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then stringBuilder.Append(c) End If Next Return stringBuilder.ToString().ToLower() End Function 

você pode usar a extensão de string do pacote nuget MMLib.Extensions:

 using MMLib.RapidPrototyping.Generators; public void ExtensionsExample() { string target = "aácčeéií"; Assert.AreEqual("aacceeii", target.RemoveDiacritics()); } 

Página Nuget: https://www.nuget.org/packages/MMLib.Extensions/ Site do projeto Codeplex https://mmlib.codeplex.com/

É engraçado que uma pergunta como essa possa ter tantas respostas, mas nenhuma atende aos meus requisitos 🙂 Existem tantas linguagens por aí que uma solução agnóstica de linguagem completa não é realmente possível, já que outras pessoas mencionaram que o FormC ou o FormD estão dando problemas.

Como a pergunta original estava relacionada ao francês, a resposta mais simples é de fato

  public static string ConvertWesternEuropeanToASCII(this string str) { return Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(str)); } 

1251 deve ser substituído pelo código de codificação do idioma de input.

No entanto, isso substitui apenas um caractere por um caractere. Como também estou trabalhando com o alemão como input, fiz uma conversão manual

  public static string LatinizeGermanCharacters(this string str) { StringBuilder sb = new StringBuilder(str.Length); foreach (char c in str) { switch (c) { case 'ä': sb.Append("ae"); break; case 'ö': sb.Append("oe"); break; case 'ü': sb.Append("ue"); break; case 'Ä': sb.Append("Ae"); break; case 'Ö': sb.Append("Oe"); break; case 'Ü': sb.Append("Ue"); break; case 'ß': sb.Append("ss"); break; default: sb.Append(c); break; } } return sb.ToString(); } 

Pode não oferecer o melhor desempenho, mas pelo menos é muito fácil de ler e ampliar. Regex é um NO GO, muito mais lento que qualquer coisa de char / string.

Eu também tenho um método muito simples para remover o espaço:

  public static string RemoveSpace(this string str) { return str.Replace(" ", string.Empty); } 

Eventualmente, estou usando uma combinação de todas as três extensões acima:

  public static string LatinizeAndConvertToASCII(this string str, bool keepSpace = false) { str = str.LatinizeGermanCharacters().ConvertWesternEuropeanToASCII(); return keepSpace ? str : str.RemoveSpace(); } 

E uma pequena unidade de teste para isso (não exaustiva) que passa com sucesso.

  [TestMethod()] public void LatinizeAndConvertToASCIITest() { string europeanStr = "Bonjour ça va? C'est l'été! Ich möchte ä Ä á à â ê é è ë Ë É ï Ï î í ì ó ò ô ö Ö Ü ü ù ú û Û ý Ý ç Ç ñ Ñ"; string expected = "Bonjourcava?C'estl'ete!IchmoechteaeAeaaaeeeeEEiIiiiooooeOeUeueuuuUyYcCnN"; string actual = europeanStr.LatinizeAndConvertToASCII(); Assert.AreEqual(expected, actual); } 

Experimente o pacote HelperSharp .

Existe um método RemoveAccents:

  public static string RemoveAccents(this string source) { //8 bit characters byte[] b = Encoding.GetEncoding(1251).GetBytes(source); // 7 bit characters string t = Encoding.ASCII.GetString(b); Regex re = new Regex("[^a-zA-Z0-9]=-_/"); string c = re.Replace(t, " "); return c; } 
 Imports System.Text Imports System.Globalization Public Function DECODE(ByVal x As String) As String Dim sb As New StringBuilder For Each c As Char In x.Normalize(NormalizationForm.FormD).Where(Function(a) CharUnicodeInfo.GetUnicodeCategory(a) <> UnicodeCategory.NonSpacingMark) sb.Append(c) Next Return sb.ToString() End Function 

O que essa pessoa disse:

Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(text));

Ele realmente divide os gostos de å que é um caractere (que é o código de caractere 00E5 , não 0061 mais o modificador 030A que pareceria o mesmo) em a plus algum tipo de modificador, e então a conversão ASCII remove o modificador, deixando a única a .

Eu realmente gosto do código conciso e funcional fornecido pelo azrafe7 . Então, eu mudei um pouco para convertê-lo em um método de extensão:

 public static class StringExtensions { public static string RemoveDiacritics(this string text) { const string SINGLEBYTE_LATIN_ASCII_ENCODING = "ISO-8859-8"; if (string.IsNullOrEmpty(text)) { return string.Empty; } return Encoding.ASCII.GetString( Encoding.GetEncoding(SINGLEBYTE_LATIN_ASCII_ENCODING).GetBytes(text)); } } 

Popping esta biblioteca aqui, se você ainda não considerou. Parece que há uma gama completa de testes unitários com ele.

https://github.com/thomasgalliker/Diacritics.NET