Как изменить диакритические знаки на недиакритические

Я нашел ответ, как удалить диакритические знаки в стеке, но не могли бы вы сказать, возможно ли заменить диакритические символы на недиакритические?

Ох.. и я думаю о.NET (или другой, если это невозможно)

5 ответов

Решение

Копирую из собственного ответа на другой вопрос:

Вместо того, чтобы создавать свою собственную таблицу, вы могли бы вместо этого преобразовать текст в форму нормализации D, где символы представлены как базовый символ плюс диакритические знаки (например, "á" будет заменено на "a", за которым следует сочетание острого акцента). Затем вы можете удалить все, что не является буквой ASCII.

Таблицы все еще существуют, но теперь они из стандарта Unicode.

Вы также можете попробовать NFKD вместо NFD, чтобы поймать еще больше случаев.

Рекомендации:

Поскольку никто не удосужился опубликовать код для этого, вот он:

    // \p{Mn} or \p{Non_Spacing_Mark}: 
    //   a character intended to be combined with another 
    //   character without taking up extra space 
    //   (e.g. accents, umlauts, etc.). 
    private readonly static Regex nonSpacingMarkRegex = 
        new Regex(@"\p{Mn}", RegexOptions.Compiled);

    public static string RemoveDiacritics(string text)
    {
        if (text == null)
            return string.Empty;

        var normalizedText = 
            text.Normalize(NormalizationForm.FormD);

        return nonSpacingMarkRegex.Replace(normalizedText, string.Empty);
    }

Примечание. Основная причина для этого заключается в том, что вы интегрируетесь в стороннюю систему, которая выполняет только ascii, но ваши данные в Unicode. Это распространено. Ваши варианты в основном: удалить акцентированные символы или попытаться удалить акценты из акцентированных символов, чтобы попытаться сохранить как можно больше исходного ввода. Очевидно, что это не идеальное решение, но это на 80% лучше, чем просто удалить любой символ выше ascii 127.

Возможно, стоит отступить и подумать, почему вы хотите это сделать. Если вы пытаетесь устранить различия символов, которые считаете незначительными, вам следует взглянуть на алгоритм сопоставления Юникод. Это стандартный способ игнорировать различия, такие как регистр или диакритические знаки, при сравнении строк для поиска или сортировки.

Если вы планируете отображать измененный текст, подумайте о своей аудитории. То, что вы можете безопасно отфильтровать, зависит от локали. В американском английском "Igloo" = "igloo" и "resume" = "résumé", но на турецком языке строчная буква I - ı (без точки), а на французском языке cote означает кавычку, côté означает сторону, а cote означает берег. Таким образом, язык сопоставления определяет, какие различия значимы.

Если удаление диакритических знаков является правильным решением для вашего приложения, то безопаснее всего создать собственную таблицу, в которую вы явно добавляете символы, которые хотите преобразовать.

Общий, автоматизированный подход может быть разработан с использованием декомпозиции Unicode. При этом вы можете разложить символ с диакритическими знаками на "объединение" символов (диакритических знаков) и базового символа, с которым они объединяются. Отфильтруйте все, что является комбинирующим символом, и у вас должны быть "недиакритические".

Однако отсутствие дискриминации в автоматизированном методе может иметь некоторые неожиданные последствия. Я бы порекомендовал много тестов на репрезентативной части текста.

Для простого примера:

Чтобы удалить диакритические знаки из строки:

string newString = myDiacriticsString.Normalize(NormalizationForm.FormD);

Мой сайт вводит данные из внешних источников, которые имеют много странных символов. Я написал следующую функцию C# для замены акцентированных символов и удаления неамериканских символов клавиатуры с помощью Regex:

    using System.Text;
    using System.Text.RegularExpressions;

    internal static string SanitizeString(string source)
    {
        return Regex.Replace(source.Normalize(NormalizationForm.FormD), @"[^A-Za-z 0-9 \.,\?'""!@#\$%\^&\*\(\)-_=\+;:<>\/\\\|\}\{\[\]`~]*", string.Empty).Trim();    
    }

Надеюсь, поможет.

Другие вопросы по тегам