Удалите диакритические знаки (ń ǹ ň ñ ṅ ņ ṇ ṋ ṉ ̈ ɲ ƞ ᶇ ɳ ȵ) от символов Unicode

Существенно Вы не будете в состоянии сохранить то же качество, потому что jpg (насколько я знаю), всегда с потерями даже с максимально возможными качественными настройками.

, Если разрядно-точное качество действительно важно, рассмотрите использование png, который имеет некоторые режимы, которые без потерь.

85
задан halfer 15 November 2015 в 23:21
поделиться

10 ответов

Я недавно проделал это на Java:

public static final Pattern DIACRITICS_AND_FRIENDS
    = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");

private static String stripDiacritics(String str) {
    str = Normalizer.normalize(str, Normalizer.Form.NFD);
    str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
    return str;
}

Это будет работать, как вы указали:

stripDiacritics("Björn")  = Bjorn

, но это не удастся, например, в Белостоке, потому что символ ł не является диакритическим знаком.

Если вы хотите получить полноценный упроститель строки, вам потребуется второй раунд очистки для некоторых дополнительных специальных символов, не являющихся диакритическими знаками. На этой карте я включил наиболее распространенные специальные символы, которые встречаются в именах наших клиентов. Это не полный список, но он даст вам представление о том, как его расширить. ImmutableMap - это простой класс из google-коллекций.

public class StringSimplifier {
    public static final char DEFAULT_REPLACE_CHAR = '-';
    public static final String DEFAULT_REPLACE = String.valueOf(DEFAULT_REPLACE_CHAR);
    private static final ImmutableMap<String, String> NONDIACRITICS = ImmutableMap.<String, String>builder()

        //Remove crap strings with no sematics
        .put(".", "")
        .put("\"", "")
        .put("'", "")

        //Keep relevant characters as seperation
        .put(" ", DEFAULT_REPLACE)
        .put("]", DEFAULT_REPLACE)
        .put("[", DEFAULT_REPLACE)
        .put(")", DEFAULT_REPLACE)
        .put("(", DEFAULT_REPLACE)
        .put("=", DEFAULT_REPLACE)
        .put("!", DEFAULT_REPLACE)
        .put("/", DEFAULT_REPLACE)
        .put("\\", DEFAULT_REPLACE)
        .put("&", DEFAULT_REPLACE)
        .put(",", DEFAULT_REPLACE)
        .put("?", DEFAULT_REPLACE)
        .put("°", DEFAULT_REPLACE) //Remove ?? is diacritic?
        .put("|", DEFAULT_REPLACE)
        .put("<", DEFAULT_REPLACE)
        .put(">", DEFAULT_REPLACE)
        .put(";", DEFAULT_REPLACE)
        .put(":", DEFAULT_REPLACE)
        .put("_", DEFAULT_REPLACE)
        .put("#", DEFAULT_REPLACE)
        .put("~", DEFAULT_REPLACE)
        .put("+", DEFAULT_REPLACE)
        .put("*", DEFAULT_REPLACE)

        //Replace non-diacritics as their equivalent characters
        .put("\u0141", "l") // BiaLystock
        .put("\u0142", "l") // Bialystock
        .put("ß", "ss")
        .put("æ", "ae")
        .put("ø", "o")
        .put("©", "c")
        .put("\u00D0", "d") // All Ð ð from http://de.wikipedia.org/wiki/%C3%90
        .put("\u00F0", "d")
        .put("\u0110", "d")
        .put("\u0111", "d")
        .put("\u0189", "d")
        .put("\u0256", "d")
        .put("\u00DE", "th") // thorn Þ
        .put("\u00FE", "th") // thorn þ
        .build();


    public static String simplifiedString(String orig) {
        String str = orig;
        if (str == null) {
            return null;
        }
        str = stripDiacritics(str);
        str = stripNonDiacritics(str);
        if (str.length() == 0) {
            // Ugly special case to work around non-existing empty strings
            // in Oracle. Store original crapstring as simplified.
            // It would return an empty string if Oracle could store it.
            return orig;
        }
        return str.toLowerCase();
    }

    private static String stripNonDiacritics(String orig) {
        StringBuffer ret = new StringBuffer();
        String lastchar = null;
        for (int i = 0; i < orig.length(); i++) {
            String source = orig.substring(i, i + 1);
            String replace = NONDIACRITICS.get(source);
            String toReplace = replace == null ? String.valueOf(source) : replace;
            if (DEFAULT_REPLACE.equals(lastchar) && DEFAULT_REPLACE.equals(toReplace)) {
                toReplace = "";
            } else {
                lastchar = toReplace;
            }
            ret.append(toReplace);
        }
        if (ret.length() > 0 && DEFAULT_REPLACE_CHAR == ret.charAt(ret.length() - 1)) {
            ret.deleteCharAt(ret.length() - 1);
        }
        return ret.toString();
    }

    /*
    Special regular expression character ranges relevant for simplification -> see http://docstore.mik.ua/orelly/perl/prog3/ch05_04.htm
    InCombiningDiacriticalMarks: special marks that are part of "normal" ä, ö, î etc..
        IsSk: Symbol, Modifier see http://www.fileformat.info/info/unicode/category/Sk/list.htm
        IsLm: Letter, Modifier see http://www.fileformat.info/info/unicode/category/Lm/list.htm
     */
    public static final Pattern DIACRITICS_AND_FRIENDS
        = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");


    private static String stripDiacritics(String str) {
        str = Normalizer.normalize(str, Normalizer.Form.NFD);
        str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("");
        return str;
    }
}
77
ответ дан 24 November 2019 в 08:19
поделиться

Основной пакет java.text был разработан для решения этого варианта использования (соответствие строки, не обращая внимания на диакритические знаки, регистр и т. д.).

Настройте Collator для сортировки по ПЕРВИЧНЫМ различиям в символах. При этом создайте CollationKey для каждой строки. Если весь ваш код написан на Java, вы можете напрямую использовать CollationKey . Если вам нужно сохранить ключи в базе данных или в индексе другого типа, вы можете преобразовать его в массив байтов .

Эти классы используют данные сворачивания регистра стандарта Unicode для определять, какие символы эквивалентны, и поддерживать различные стратегии декомпозиции .

Collator c = Collator.getInstance();
c.setStrength(Collator.PRIMARY);
Map<CollationKey, String> dictionary = new TreeMap<CollationKey, String>();
dictionary.put(c.getCollationKey("Björn"), "Björn");
...
CollationKey query = c.getCollationKey("bjorn");
System.out.println(dictionary.get(query)); // --> "Björn"

Обратите внимание, что подборщики зависят от локали. Это связано с тем, что «алфавитный порядок» в разных регионах различается (и даже со временем, как в случае с испанским языком). Класс Collator избавляет вас от необходимости отслеживать все эти правила и поддерживать их в актуальном состоянии.

23
ответ дан 24 November 2019 в 08:19
поделиться

Вы можете использовать класс нормализатора из java.text :

System.out.println(new String(Normalizer.normalize("ń ǹ ň ñ ṅ ņ ṇ ṋ", Normalizer.Form.NFKD).getBytes("ascii"), "ascii"));

Но есть еще кое-что, что нужно сделать, поскольку Java делает странные вещи с неконвертируемыми символами Unicode (он не игнорирует их и не генерирует исключение). Но я думаю, вы могли бы использовать это как отправную точку.

11
ответ дан 24 November 2019 в 08:19
поделиться

На сайте Unicode есть черновик отчета о сворачивании символов, в котором есть много соответствующего материала. См. В частности раздел 4.1. «Алгоритм складывания».

Здесь обсуждение и реализация удаления диакритических маркеров с использованием Perl.

Эти существующие вопросы SO связаны:

10
ответ дан 24 November 2019 в 08:19
поделиться

Unicode имеет определенные диатрические символы (которые являются составными символами), и строка может быть преобразована таким образом, чтобы символ и диатрика были разделены. Затем вы можете просто удалить диатрику из строки, и все, в основном, готово.

Для получения дополнительной информации о нормализации, декомпозиции и эквивалентности см. Стандарт Unicode на домашней странице Unicode .

Однако то, как вы можете этого добиться, зависит от платформы / OS / ..., над которой вы работаете. Если вы используете .NET, вы можете использовать метод String.Normalize , принимающий перечисление System.Text.NormalizationForm .

Затем вы можете просто удалить диатрику из строки, и все, в основном, готово.

Для получения дополнительной информации о нормализации, декомпозиции и эквивалентности см. Стандарт Unicode на домашней странице Unicode .

Однако то, как вы можете этого добиться, зависит от платформы / OS / ..., над которой вы работаете. Если вы используете .NET, вы можете использовать метод String.Normalize , принимающий перечисление System.Text.NormalizationForm .

Затем вы можете просто удалить диатрику из строки, и в основном все готово.

Для получения дополнительной информации о нормализации, декомпозиции и эквивалентности см. Стандарт Unicode на домашней странице Unicode .

Однако то, как вы можете этого добиться, зависит от платформы / OS / ..., над которой вы работаете. Если вы используете .NET, вы можете использовать метод String.Normalize , принимающий перечисление System.Text.NormalizationForm .

2
ответ дан 24 November 2019 в 08:19
поделиться

Самый простой способ (для меня) - просто поддерживать разреженный массив сопоставления, который просто преобразует ваши кодовые точки Unicode в отображаемые строки.

Например:

start    = 0x00C0
size     = 23
mappings = {
    "A","A","A","A","A","A","AE","C",
    "E","E","E","E","I","I","I", "I",
    "D","N","O","O","O","O","O"
}
start    = 0x00D8
size     = 6
mappings = {
    "O","U","U","U","U","Y"
}
start    = 0x00E0
size     = 23
mappings = {
    "a","a","a","a","a","a","ae","c",
    "e","e","e","e","i","i","i", "i",
    "d","n","o","o","o","o","o"
}
start    = 0x00F8
size     = 6
mappings = {
    "o","u","u","u","u","y"
}
: : :

Использование sparse массив позволит вам эффективно представлять замены, даже если они находятся в широко разнесенных разделах таблицы Unicode. Замена строк позволит произвольным последовательностям заменить ваши диакритические знаки (например, æ графема становится ae ).

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

2
ответ дан 24 November 2019 в 08:19
поделиться

В Windows и .NET я просто конвертирую, используя строковую кодировку. Таким образом я избегаю ручного сопоставления и кодирования.

Попробуйте поиграть с кодировкой строк.

2
ответ дан 24 November 2019 в 08:19
поделиться

На что следует обратить внимание: если вы пойдете по пути попытки получить единственный «перевод» каждого слова, вы можете упустить некоторые возможные альтернативы.

Например, на немецком языке, при замене «s-set» некоторые люди могут использовать «B», а другие - «ss». Или заменив umlauted o на «o» или «oe». Любое решение, которое вы придумаете, в идеале, я думаю, должно включать оба.

2
ответ дан 24 November 2019 в 08:19
поделиться

Для справки в будущем, вот метод расширения C #, который удаляет акценты.

public static class StringExtensions
{
    public static string RemoveDiacritics(this string str)
    {
        return new string(
            str.Normalize(NormalizationForm.FormD)
                .Where(c => CharUnicodeInfo.GetUnicodeCategory(c) != 
                            UnicodeCategory.NonSpacingMark)
                .ToArray());
    }
}
static void Main()
{
    var input = "ŃŅŇ ÀÁÂÃÄÅ ŢŤţť Ĥĥ àáâãäå ńņň";
    var output = input.RemoveDiacritics();
    Debug.Assert(output == "NNN AAAAAA TTtt Hh aaaaaa nnn");
}
1
ответ дан 24 November 2019 в 08:19
поделиться

Обратите внимание, что не все эти метки являются просто «метками» на некоторых " обычный "символ", который можно удалить, не меняя смысла.

В шведском языке å ä и ö - настоящие и правильные первоклассные символы, а не какой-то «вариант» какого-то другого символа. Они звучат иначе, чем все другие символы, они сортируются по-другому и заставляют слова менять значение («mätt» и «matt» - это два разных слова).

​​
4
ответ дан 24 November 2019 в 08:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: