Как удалить акценты в строке?

Возможный дубликат:
Как удалить диакритические знаки (акценты) из строки в .NET?

У меня есть следующая строка

áéíóú

который мне нужно преобразовать в

aeiou

Как я могу это достичь? (Мне не нужно сравнивать, мне нужна новая строка для сохранения)


Не дубликат Как удалить диакритические символы (акценты) из строки в .NET?. Принятый ответ там ничего не объясняет и почему я его "возобновил".

Ответ 1

Это зависит от требований. Для большинства применений, нормализация к NFD и последующая фильтрация всех комбинаций символов. В некоторых случаях нормализация к NFKD более подходит (если вы также хотите удалить некоторые дополнительные различия между символами).

Некоторые другие отличия не будут улавливаться этим, особенно ласковыми штрихами. Там также нет четкого неязыкового метода для некоторых (следует ли считать, что ł эквивалентно l или w?), Поэтому вам может потребоваться настроить вне этого.

Также есть случаи, когда NFD и NFKD работают не так, как ожидалось, чтобы обеспечить согласованность между версиями Unicode.

Следовательно:

public static IEnumerable<char> RemoveDiacriticsEnum(string src, bool compatNorm, Func<char, char> customFolding)
{
    foreach(char c in src.Normalize(compatNorm ? NormalizationForm.FormKD : NormalizationForm.FormD))
    switch(CharUnicodeInfo.GetUnicodeCategory(c))
    {
      case UnicodeCategory.NonSpacingMark:
      case UnicodeCategory.SpacingCombiningMark:
      case UnicodeCategory.EnclosingMark:
        //do nothing
        break;
      default:
        yield return customFolding(c);
        break;
    }
}
public static IEnumerable<char> RemoveDiacriticsEnum(string src, bool compatNorm)
{
  return RemoveDiacritics(src, compatNorm, c => c);
}
public static string RemoveDiacritics(string src, bool compatNorm, Func<char, char> customFolding)
{
  StringBuilder sb = new StringBuilder();
  foreach(char c in RemoveDiacriticsEnum(src, compatNorm, customFolding))
    sb.Append(c);
  return sb.ToString();
}
public static string RemoveDiacritics(string src, bool compatNorm)
{
  return RemoveDiacritics(src, compatNorm, c => c);
}

Здесь мы по умолчанию для проблемных случаев, упомянутых выше, которые просто игнорируют их. Мы также разделили построение строки из генерации перечисления символов, поэтому нам не нужно расточительно в тех случаях, когда нет необходимости в манипулировании строками результата (скажем, мы собирались написать символы для вывода следующего или сделать еще несколько char -by- char).

Пример для чего-то, где мы хотели также преобразовать ł и Ł в l и L, но не имел других специализированных проблем, которые могли бы использовать:

private static char NormaliseLWithStroke(char c)
{
  switch(c)
  {
     case 'ł':
       return 'l';
     case 'Ł':
       return 'L';
     default:
       return c;
  }
}

Используя это с помощью вышеперечисленных методов, он будет объединяться для удаления штриха в этом случае вместе с разложимой диакритикой.

Ответ 2

public string RemoveDiacritics(string input)
{
    string stFormD = input.Normalize(NormalizationForm.FormD);
    int len = stFormD.Length;
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < len; i++)
    {
        System.Globalization.UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[i]);
        if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
        {
            sb.Append(stFormD[i]);
        }
    }
    return (sb.ToString().Normalize(NormalizationForm.FormC));
}