Can.NET преобразование Unicode в ASCII для удаления "умных кавычек" и т. д.?
некоторые наши пользователи используют почтовые клиенты, которые не могут справиться с Unicode, даже если кодировка и т. д. правильно установлены в заголовках почты.
Я хотел бы "нормализовать" контент, который они получают. Самая большая проблема, которую мы имеем, - это пользователи копируют контент из Microsoft Word в наше веб-приложение, которое затем пересылает этот контент по электронной почте, включая фракции, смарт-кавычки и все другие расширенные символы Юникода, которые Word услужливо вставляет для вы.
Я предполагаю, что нет определенного решения для этого, но прежде чем я сяду и начну писать большие таблицы поиска, есть ли какой-то встроенный метод, который заставит меня начать?
в основном задействованы три фазы.
во-первых, зачистка акцентов от иначе-нормальных букв-решение этого здесь
This paragraph contains “smart quotes” and áccénts and ½ of the problem is fractions
идет
This paragraph contains “smart quotes” and accents and ½ of the problem is fractions
во-вторых, замена отдельных символов Юникода их ASCII эквивалент, чтобы дать:
This paragraph contains "smart quotes" and accents and ½ of the problem is fractions
это та часть, где я надеюсь, что есть решение, прежде чем я реализую свой собственный. Наконец, замена определенных символов подходящей последовательностью ASCII-от ½ до 1/2 и т. д., которая, я уверен, изначально не поддерживается какой - либо магией Unicode, но кто-то мог написать подходящую таблицу поиска, которую я могу повторно использовать.
какие идеи?
4 ответов
спасибо всем за очень полезные ответы. Я понимаю, что фактический вопрос не "как я могу преобразовать любой символ Юникода в его резервный код ASCII" - вопрос в том, " как я могу преобразовать символы Юникода мои клиенты жалуются в их ASCII fallbacks"?
другими словами-нам не нужно универсальное решение; нам нужно решение, которое будет работать 99% времени, для англоговорящих клиентов, вставляющих англоязычный контент из Word и другие сайты в нашем приложении. С этой целью я проанализировал восемь лет сообщений, отправленных через нашу систему в поисках символов, которые не представимы в кодировке ASCII, используя этот тест:
///<summary>Determine whether the supplied character is
///using ASCII encoding.</summary>
bool IsAscii(char inputChar) {
var ascii = new ASCIIEncoding();
var asciiChar = (char)(ascii.GetBytes(inputChar.ToString())[0]);
return(asciiChar == inputChar);
}
затем я прошел через результирующий набор непредставимых символов и вручную назначил соответствующую строку замены. Весь лот упакован в метод расширения, поэтому вы можете вызвать myString.Asciify (), чтобы преобразовать вашу строку в разумную ASCII-кодирование приближения.
public static class StringExtensions {
private static readonly Dictionary<char, string> Replacements = new Dictionary<char, string>();
/// <summary>Returns the specified string with characters not representable in ASCII codepage 437 converted to a suitable representative equivalent. Yes, this is lossy.</summary>
/// <param name="s">A string.</param>
/// <returns>The supplied string, with smart quotes, fractions, accents and punctuation marks 'normalized' to ASCII equivalents.</returns>
/// <remarks>This method is lossy. It's a bit of a hack that we use to get clean ASCII text for sending to downlevel e-mail clients.</remarks>
public static string Asciify(this string s) {
return (String.Join(String.Empty, s.Select(c => Asciify(c)).ToArray()));
}
private static string Asciify(char x) {
return Replacements.ContainsKey(x) ? (Replacements[x]) : (x.ToString());
}
static StringExtensions() {
Replacements['’'] = "'"; // 75151 occurrences
Replacements['–'] = "-"; // 23018 occurrences
Replacements['‘'] = "'"; // 9783 occurrences
Replacements['”'] = "\""; // 6938 occurrences
Replacements['“'] = "\""; // 6165 occurrences
Replacements['…'] = "..."; // 5547 occurrences
Replacements['£'] = "GBP"; // 3993 occurrences
Replacements['•'] = "*"; // 2371 occurrences
Replacements[' '] = " "; // 1529 occurrences
Replacements['é'] = "e"; // 878 occurrences
Replacements['ï'] = "i"; // 328 occurrences
Replacements['´'] = "'"; // 226 occurrences
Replacements['—'] = "-"; // 133 occurrences
Replacements['·'] = "*"; // 132 occurrences
Replacements['„'] = "\""; // 102 occurrences
Replacements['€'] = "EUR"; // 95 occurrences
Replacements['®'] = "(R)"; // 91 occurrences
Replacements['¹'] = "(1)"; // 80 occurrences
Replacements['«'] = "\""; // 79 occurrences
Replacements['è'] = "e"; // 79 occurrences
Replacements['á'] = "a"; // 55 occurrences
Replacements['™'] = "TM"; // 54 occurrences
Replacements['»'] = "\""; // 52 occurrences
Replacements['ç'] = "c"; // 52 occurrences
Replacements['½'] = "1/2"; // 48 occurrences
Replacements[''] = "-"; // 39 occurrences
Replacements['°'] = " degrees "; // 33 occurrences
Replacements['ä'] = "a"; // 33 occurrences
Replacements['É'] = "E"; // 31 occurrences
Replacements['‚'] = ","; // 31 occurrences
Replacements['ü'] = "u"; // 30 occurrences
Replacements['í'] = "i"; // 28 occurrences
Replacements['ë'] = "e"; // 26 occurrences
Replacements['ö'] = "o"; // 19 occurrences
Replacements['à'] = "a"; // 19 occurrences
Replacements['¬'] = " "; // 17 occurrences
Replacements['ó'] = "o"; // 15 occurrences
Replacements['â'] = "a"; // 13 occurrences
Replacements['ñ'] = "n"; // 13 occurrences
Replacements['ô'] = "o"; // 10 occurrences
Replacements['¨'] = ""; // 10 occurrences
Replacements['å'] = "a"; // 8 occurrences
Replacements['ã'] = "a"; // 8 occurrences
Replacements['ˆ'] = ""; // 8 occurrences
Replacements['©'] = "(c)"; // 6 occurrences
Replacements['Ä'] = "A"; // 6 occurrences
Replacements['Ï'] = "I"; // 5 occurrences
Replacements['ò'] = "o"; // 5 occurrences
Replacements['ê'] = "e"; // 5 occurrences
Replacements['î'] = "i"; // 5 occurrences
Replacements['Ü'] = "U"; // 5 occurrences
Replacements['Á'] = "A"; // 5 occurrences
Replacements['ß'] = "ss"; // 4 occurrences
Replacements['¾'] = "3/4"; // 4 occurrences
Replacements['È'] = "E"; // 4 occurrences
Replacements['¼'] = "1/4"; // 3 occurrences
Replacements['†'] = "+"; // 3 occurrences
Replacements['³'] = "'"; // 3 occurrences
Replacements['²'] = "'"; // 3 occurrences
Replacements['Ø'] = "O"; // 2 occurrences
Replacements['¸'] = ","; // 2 occurrences
Replacements['Ë'] = "E"; // 2 occurrences
Replacements['ú'] = "u"; // 2 occurrences
Replacements['Ö'] = "O"; // 2 occurrences
Replacements['û'] = "u"; // 2 occurrences
Replacements['Ú'] = "U"; // 2 occurrences
Replacements['Œ'] = "Oe"; // 2 occurrences
Replacements['º'] = "?"; // 1 occurrences
Replacements['‰'] = "0/00"; // 1 occurrences
Replacements['Å'] = "A"; // 1 occurrences
Replacements['ø'] = "o"; // 1 occurrences
Replacements['˜'] = "~"; // 1 occurrences
Replacements['æ'] = "ae"; // 1 occurrences
Replacements['ù'] = "u"; // 1 occurrences
Replacements['‹'] = "<"; // 1 occurrences
Replacements['±'] = "+/-"; // 1 occurrences
}
}
обратите внимание, что там есть некоторые довольно странные отступления-как этот:
Replacements['³'] = "'"; // 3 occurrences
Replacements['²'] = "'"; // 3 occurrences
это потому, что у одного из наших пользователей есть программа, которая преобразует открытые/закрытые смарт-кавычки в 2 и 3 (например : он сказал 2hello3), и никто никогда не использовал их для представления экспоненции, поэтому это, вероятно, будет работать довольно хорошо для нас, но YMMV.
у меня были некоторые проблемы с этим, используя список строк, изначально построенный в Word. Я обнаружил, что с помощью простого "String".replace(current char/string, new char/string)
команда отлично работает. Точный код, который я использовал, был для смарт-кавычек или, если быть точным: left", right ", left 'и right' выглядит следующим образом:
StringName = StringName.Replace(ChrW(8216), "'") ' Replaces any left ' with a normal '
StringName = StringName.Replace(ChrW(8217), "'") ' Replaces any right ' with a normal '
StringName = StringName.Replace(ChrW(8220), """") ' Replace any left " with a normal "
StringName = StringName.Replace(ChrW(8221), """") ' Replace any right " with a normal "
Я надеюсь, что это поможет любому, кто все еще имеет эту проблему!
есть какой-то встроенный метод, который начнем?
первое, что я бы попытался, это преобразовать текст в NFKD форма нормализации С нормализуют метод строк. Это предложение упоминается в ответе на вопрос, который вы связали, но я рекомендую использовать NFKD вместо NFD, потому что NFKD удалит нежелательные типографские различия (например, NBSP → space или ℂ → C).
вы также можете сделайте общие замены категория Юникода. Например, Pd можно заменить на -
, Nd могут быть заменены на соответствующие 0
-9
цифра и Mn могут быть заменены пустой строкой (для удаления акцентов).
но кто-то мог написать подходящая таблица поиска, которую я могу повторно использовать.
вы можете попробовать использовать данные из программы Unidecode, или CLDR.
редактировать: Есть огромная диаграмма замещения здесь.
вы никогда не должны пытаться конвертировать Unicode в ASCII, потому что в конечном итоге у вас будет больше проблем, чем решение.
Это похоже на попытку поместить 1,114,112 кодовые точки (Unicode 6.0) всего в 128 символов.
вы думаете у вас получится?
кстати, есть много кавычек в Unicode, а не только те, которые упомянуты вами, а также если вы хотите сделать преобразование в любом случае помните, что преобразования будут зависеть от место действия.
Регистрация ОИТ - содержит наиболее полные процедуры преобразования Unicode.