¿Cómo elimino diacríticos (acentos) de una cadena en .NET?

Estoy tratando de convertir algunas cadenas que están en francés canadiense y, básicamente, me gustaría poder sacar los acentos franceses en las letras mientras guardo la letra. (Por ejemplo, convertir é a e , por lo que crème brûlée se convertiría en creme brulee )

¿Cuál es el mejor método para lograr esto?

    No he usado este método, pero Michael Kaplan describe un método para hacerlo en su publicación de blog (con un título confuso) que habla sobre despojar a los diacríticos: Stripping es un trabajo interesante (también conocido como Sobre el significado de los personajes sin sentido, también conocido como All Mn son no espaciados, pero algunos son más espaciados que otros)

     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); } 

    Tenga en cuenta que este es un seguimiento de su publicación anterior: Stripping diacritics ….

    El enfoque usa String.Normalize para dividir la cadena de entrada en glifos constituyentes (básicamente separando los caracteres “base” de los signos diacríticos) y luego escanea el resultado y conserva solo los caracteres base. Es un poco complicado, pero realmente estás viendo un problema complicado.

    Por supuesto, si te estás limitando al francés, probablemente te saldrías con la simple estrategia basada en tablas en Cómo eliminar acentos y tilde en C ++ std :: string , tal como recomienda @David Dibben.

    esto hizo el truco para mí …

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

    rápido y corto!

    En caso de que alguien esté interesado, estaba buscando algo similar y terminé escribiendo lo siguiente:

      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 underscores } 

    En caso de que alguien esté interesado, aquí está el equivalente de 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 

    A menudo utilizo un método de extensión basado en otra versión que encontré aquí (ver Reemplazar caracteres en C # (ascii) ) Una explicación rápida:

    • Normalizar para formar D divide los caracteres como è en e y en no-espacio `
    • A partir de esto, los personajes que se separan se eliminan
    • El resultado se normaliza de vuelta a la forma C (no estoy seguro si esto es necesario)

    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); } } 

    Necesitaba algo que convirtiera todos los caracteres Unicode principales y la respuesta elegida me dejó unos pocos, así que creé una versión de convert_accented_characters($str) de CodeIgniter en C # que es fácilmente personalizable:

     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 

    La página de código de griego (ISO) puede hacerlo

    La información sobre esta página de códigos está en System.Text.Encoding.GetEncodings() . Obtenga más información en: https://msdn.microsoft.com/pt-br/library/system.text.encodinginfo.getencoding(v=vs.110).aspx

    Griego (ISO) tiene la página de códigos 28597 y el nombre iso-8859-7 .

    Ir al 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" 

    Entonces, escribe esta función …

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

    Tenga en cuenta que … Encoding.GetEncoding("iso-8859-7") es equivalente a Encoding.GetEncoding(28597) porque primero es el nombre y, en segundo lugar, la página de códigos de Encoding.

    Esto funciona bien en Java.

    Básicamente convierte todos los caracteres acentuados en sus contrapartes deAccented seguidas de sus signos diacríticos combinados. Ahora puede usar una expresión regular para quitar los signos 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 ES LA VERSIÓN VB (Funciona con GREEK):

    Imports System.Text

    Sistema de Importaciones.Globalización

     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 

    Así es como reemplazo los caracteres diacríticos por los que no son diacríticos en todos mis progtwigs .NET

    DO#:

     //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 

    puede usar la extensión de cadena del paquete nuget MMLib.Extensions:

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

    Página de Nuget: https://www.nuget.org/packages/MMLib.Extensions/ Sitio del proyecto Codeplex https://mmlib.codeplex.com/

    Es curioso que una pregunta así pueda obtener tantas respuestas, pero ninguna se ajusta a mis requisitos 🙂 Hay tantos idiomas alrededor, una solución agnóstica de idioma completo no es realmente posible, ya que otros han mencionado que el FormC o el FormD están dando problemas.

    Dado que la pregunta original estaba relacionada con el francés, la respuesta de trabajo más simple es de hecho

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

    1251 debe ser reemplazado por el código de encoding del idioma de entrada.

    Sin embargo, esto reemplaza solo un personaje por un personaje. Como también estoy trabajando con el alemán como entrada, hice una conversión 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(); } 

    Puede que no ofrezca el mejor rendimiento, pero al menos es muy fácil de leer y ampliar. Regex es un NO GO, mucho más lento que cualquier cosa de char / string.

    También tengo un método muy simple para eliminar espacio:

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

    Eventualmente, estoy usando una combinación de las 3 extensiones anteriores:

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

    Y una pequeña unidad de prueba para eso (no exhaustiva) que pasa con éxito.

      [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); } 

    Pruebe el paquete HelperSharp .

    Hay un 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 

    Lo que dijo esta persona:

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

    En realidad, divide los gustos de å que es un carácter (que es el código de carácter 00E5 , no 0061 más el modificador 030A que se vería igual) en a más algún tipo de modificador, y luego la conversión ASCII elimina el modificador, dejando el único a .

    Me gusta mucho el código conciso y funcional proporcionado por azrafe7 . Entonces, lo he cambiado un poco para convertirlo a un método de extensión:

     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)); } } 

    Apareciendo esta biblioteca aquí si aún no lo has considerado. Parece que hay una gama completa de pruebas unitarias con él.

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