c# - ¿Por qué no se aplana a D cuando se quitan los acentos/diacríticos?
.net string (4)
" D with stroke " (Wikipedia) se usa en varios idiomas y parece ser considerada una letra distinta en todos ellos, y es por eso que permanece sin cambios.
Estoy usando este método para eliminar acentos de mis cadenas:
static string RemoveAccents(string input)
{
string normalized = input.Normalize(NormalizationForm.FormKD);
StringBuilder builder = new StringBuilder();
foreach (char c in normalized)
{
if (char.GetUnicodeCategory(c) !=
UnicodeCategory.NonSpacingMark)
{
builder.Append(c);
}
}
return builder.ToString();
}
pero este método deja đ como đ y no lo cambia a d, aunque d es su carácter base. puede probarlo con esta cadena de entrada "æøåáâăäĺćçčéęëěíîďđńňóôőöřůúűüýţ"
¿Qué tiene de especial la letra đ?
Esto debería funcionar
private static String RemoveDiacritics(string text)
{
String normalized = text.Normalize(NormalizationForm.FormD);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < normalized.Length; i++)
{
Char c = normalized[i];
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
sb.Append(c);
}
return sb.ToString();
}
La respuesta de por qué no funciona es que la afirmación de que "d es su carácter base" es falsa. U + 0111 (LETRA PEQUEÑA LETRA D CON MOVIMIENTO) tiene la categoría Unicode "Letra, minúscula" y no tiene mapeo de descomposición (es decir, no se descompone en "d" seguido de una marca de combinación).
"đ".Normalize(NormalizationForm.FormD)
simplemente devuelve "đ"
, que no está eliminada por el bucle porque no es una marca sin espacio.
Un problema similar existirá para "ø" y otras letras para las que Unicode no proporciona mapeo de descomposición. (Y si está tratando de encontrar el "mejor" carácter ASCII para representar una letra Unicode, este enfoque no funcionará en absoluto para el alfabeto cirílico, griego, chino u otros alfabetos no latinos; también tendrá problemas si quería transliterar "ß" a "ss", por ejemplo. Usar una biblioteca como UnidecodeSharp puede ayudar.)
Tengo que admitir que no estoy seguro de por qué funciona esto, pero seguro que parece
var str = "æøåáâăäĺćçčéęëěíîďđńňóôőöřůúűüýţ";
var noApostrophes = Encoding.ASCII.GetString(Encoding.GetEncoding("Cyrillic").GetBytes(str));
=> "aoaaaaalccceeeeiiddnnooooruuuuyt"