tildes - ¿Cómo elimino los diacríticos(acentos) de una cadena en.NET?
remove accents c# (17)
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:
- La normalización para formar D divide caracteres como è a una e y un no espaciado `
- De esto, se eliminan los caracteres nospacing.
- El resultado se normaliza de nuevo 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);
}
}
Estoy tratando de convertir algunas cadenas que están en francés canadiense y, básicamente, me gustaría poder quitar las marcas de acento francesas en las letras mientras mantengo 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?
Aparece aquí esta biblioteca si aún no la has considerado. Parece que hay una amplia gama de pruebas unitarias con él.
Así es como sustituyo los caracteres diacríticos por los no diacríticos en todos mis programas .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
ESTA ES LA VERSIÓN VB (Funciona con GRIEGO):
Sistema de importaciones. Texto
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
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<nrml.length();++i)
{
if (Character.getType(nrml.charAt(i)) != Character.NON_SPACING_MARK)
{
stripped.append(nrml.charAt(i));
}
}
return stripped.toString();
}
}
En caso de que alguien esté interesado, estaba buscando algo similar y terminé de escribir 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
}
Es gracioso que una pregunta de este tipo pueda obtener tantas respuestas y, sin embargo, ninguna se ajuste a mis requisitos :) Hay tantos idiomas disponibles, una solución completa de lenguaje no es AFAIK realmente imposible, ya que otros han mencionado que FormC o FormD están dando problemas.
Dado que la pregunta original estaba relacionada con el francés, la respuesta de trabajo más simple es
public static string ConvertWesternEuropeanToASCII(this string str)
{
return Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(str));
}
1251 debe reemplazarse por el código de codificación del idioma de entrada.
Sin embargo, esto reemplaza solo un carácter por un carácter. Como también estoy trabajando con 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 extender. Regex es un NO GO, mucho más lento que cualquier char / string.
También tengo un método muy simple para eliminar el espacio:
public static string RemoveSpace(this string str)
{
return str.Replace(" ", string.Empty);
}
Finalmente, 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 prueba de unidad 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);
}
Esto funciona bien en java.
Básicamente, convierte a todos los personajes acentuados en sus equivalentes descentrados seguidos de sus diacríticos combinados. Ahora puedes usar una expresión regular para quitarte 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("");
}
La CodePage of Greek (ISO) puede hacerlo
La información sobre esta página de códigos se encuentra 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 .
Ve 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 luego la página de códigos de Encoding.
Me gusta mucho el código conciso y funcional proporcionado por azrafe7 . Por lo tanto, lo he cambiado un poco para convertirlo en 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));
}
}
Necesitaba algo que convirtiera a todos los caracteres principales de Unicode y la respuesta votada se saliera de unos pocos, así que he creado una versión de los 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<string, string> foreign_characters = new Dictionary<string, string>
{
{ "äæǽ", "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<string, string> 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<string, string> 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
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 la eliminación de los signos diacríticos: la eliminación de bandas es un trabajo interesante (también conocido como el significado de los significados, también conocido como Todos los caracteres Mn no tienen espacios, pero algunos son más espacios 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 post anterior: Stripping diacritics ....
El enfoque utiliza String.Normalize para dividir la cadena de entrada en glifos constituyentes (básicamente, separa los caracteres "base" de los signos diacríticos) y luego escanea el resultado y retiene solo los caracteres base. Es solo un poco complicado, pero en realidad estás viendo un problema complicado.
Por supuesto, si se está limitando al francés, probablemente podría salirse con la suya con el enfoque simple basado en tablas en Cómo eliminar acentos y tilde en una cadena C ++ std :: , como lo recomienda @David Dibben.
Prueba 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;
}
esto sirvió 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!
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/
Lo que esta persona dijo:
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
modificador más de algún tipo, y luego la conversión ASCII elimina el modificador, dejando el único a
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