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

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

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

áéíóú

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

aeiou

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


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

2 ответа

Решение

Это зависит от требований. Для большинства случаев подойдет нормализация по 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);
}

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

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

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

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

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));
}
Другие вопросы по тегам