Как удалить диакритические знаки (акценты) из строки in.NET?
Я пытаюсь преобразовать некоторые строки, которые находятся на французском канадском языке и в основном, я хотел бы иметь возможность вынуть французские акцентные знаки в буквах, сохраняя письмо. (Например, преобразовать é до e, Так что crème brûlée станет creme brulee)
каков наилучший метод для достижения этой цели?
17 ответов:
Я не использовал этот метод, но Майкл Каплан описывает метод для этого в своем блоге (с запутанным названием), который говорит о снятии диакритики:стриптиз-интересная работа (ака По смыслу бессмысленно, ака все MN символы не являются интервалами, но некоторые из них более не интервал, чем другие)
static string RemoveDiacritics(string text) { var normalizedString = text.Normalize(NormalizationForm.FormD); var stringBuilder = new StringBuilder(); foreach (var c in normalizedString) { var unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c); if (unicodeCategory != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(c); } } return stringBuilder.ToString().Normalize(NormalizationForm.FormC); }обратите внимание, что это продолжение его предыдущего поста:зачистки диакритические знаки....
подход использует строку.Нормализовать чтобы разделить входную строку на составляющие глифы (в основном отделяя "базовые" символы от диакритики), а затем сканирует результат и сохраняет только базовые символы. Это просто немного сложно, но на самом деле вы смотрите на сложные проблемы.
конечно, если вы ограничиваете себя французским языком, вы, вероятно, могли бы уйти с помощью простого табличного подхода в как удалить акценты и Тильды в C++ std:: string, как рекомендовано @David Dibben.
это сделал трюк для меня...
string accentedStr; byte[] tempBytes; tempBytes = System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(accentedStr); string asciiStr = System.Text.Encoding.UTF8.GetString(tempBytes);быстрый и короткий!
в случае, если кто-то заинтересован, я искал что-то подобное и закончил писать следующее:
public static string NormalizeStringForUrl(string name) { String normalizedString = name.Normalize(NormalizationForm.FormD); StringBuilder stringBuilder = new StringBuilder(); foreach (char c in normalizedString) { switch (CharUnicodeInfo.GetUnicodeCategory(c)) { case UnicodeCategory.LowercaseLetter: case UnicodeCategory.UppercaseLetter: case UnicodeCategory.DecimalDigitNumber: stringBuilder.Append(c); break; case UnicodeCategory.SpaceSeparator: case UnicodeCategory.ConnectorPunctuation: case UnicodeCategory.DashPunctuation: stringBuilder.Append('_'); break; } } string result = stringBuilder.ToString(); return String.Join("_", result.Split(new char[] { '_' } , StringSplitOptions.RemoveEmptyEntries)); // remove duplicate underscores }
в случае, если кто-то заинтересован, вот эквивалент java:
import java.text.Normalizer; public class MyClass { public static String removeDiacritics(String input) { String nrml = Normalizer.normalize(input, Normalizer.Form.NFD); StringBuilder stripped = new StringBuilder(); for (int i=0;i<nrml.length();++i) { if (Character.getType(nrml.charAt(i)) != Character.NON_SPACING_MARK) { stripped.append(nrml.charAt(i)); } } return stripped.toString(); } }
Я часто использую метод расширения, основанный на другой версии, которую я нашел здесь (см. замена символов в C# (ascii)) Краткое описание:
- нормализация для формирования D разбивает charactes как è до e и nonspacing '
- из этого, символы nospacing удаляются
- результат нормализуется обратно в форму C (я не уверен, что это так обязательно)
код:
using System.Linq; using System.Text; using System.Globalization; // namespace here public static class Utility { public static string RemoveDiacritics(this string str) { if (null == str) return null; var chars = from c in str.Normalize(NormalizationForm.FormD).ToCharArray() let uc = CharUnicodeInfo.GetUnicodeCategory(c) where uc != UnicodeCategory.NonSpacingMark select c; var cleanStr = new string(chars.ToArray()).Normalize(NormalizationForm.FormC); return cleanStr; } // or, alternatively public static string RemoveDiacritics2(this string str) { if (null == str) return null; var chars = str .Normalize(NormalizationForm.FormD) .ToCharArray() .Where(c=> CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) .ToArray(); return new string(chars).Normalize(NormalizationForm.FormC); } }
мне нужно было что-то, что преобразует все основные символы Юникода, и проголосованный ответ оставил несколько, поэтому я создал версию Codeigniter's
convert_accented_characters($str)в C#, который легко настраивается:using System; using System.Text; using System.Collections.Generic; public static class Strings { static Dictionary<string, string> foreign_characters = new Dictionary<string, string> { { "äæǽ", "ae" }, { "öœ", "oe" }, { "ü", "ue" }, { "Ä", "Ae" }, { "Ü", "Ue" }, { "Ö", "Oe" }, { "ÀÁÂÃÄÅǺĀĂĄǍΑΆẢẠẦẪẨẬẰẮẴẲẶА", "A" }, { "àáâãåǻāăąǎªαάảạầấẫẩậằắẵẳặа", "a" }, { "Б", "B" }, { "б", "b" }, { "ÇĆĈĊČ", "C" }, { "çćĉċč", "c" }, { "Д", "D" }, { "д", "d" }, { "ÐĎĐΔ", "Dj" }, { "ðďđδ", "dj" }, { "ÈÉÊËĒĔĖĘĚΕΈẼẺẸỀẾỄỂỆЕЭ", "E" }, { "èéêëēĕėęěέεẽẻẹềếễểệеэ", "e" }, { "Ф", "F" }, { "ф", "f" }, { "ĜĞĠĢΓГҐ", "G" }, { "ĝğġģγгґ", "g" }, { "ĤĦ", "H" }, { "ĥħ", "h" }, { "ÌÍÎÏĨĪĬǏĮİΗΉΊΙΪỈỊИЫ", "I" }, { "ìíîïĩīĭǐįıηήίιϊỉịиыї", "i" }, { "Ĵ", "J" }, { "ĵ", "j" }, { "ĶΚК", "K" }, { "ķκк", "k" }, { "ĹĻĽĿŁΛЛ", "L" }, { "ĺļľŀłλл", "l" }, { "М", "M" }, { "м", "m" }, { "ÑŃŅŇΝН", "N" }, { "ñńņňʼnνн", "n" }, { "ÒÓÔÕŌŎǑŐƠØǾΟΌΩΏỎỌỒỐỖỔỘỜỚỠỞỢО", "O" }, { "òóôõōŏǒőơøǿºοόωώỏọồốỗổộờớỡởợо", "o" }, { "П", "P" }, { "п", "p" }, { "ŔŖŘΡР", "R" }, { "ŕŗřρр", "r" }, { "ŚŜŞȘŠΣС", "S" }, { "śŝşșšſσςс", "s" }, { "ȚŢŤŦτТ", "T" }, { "țţťŧт", "t" }, { "ÙÚÛŨŪŬŮŰŲƯǓǕǗǙǛŨỦỤỪỨỮỬỰУ", "U" }, { "ùúûũūŭůűųưǔǖǘǚǜυύϋủụừứữửựу", "u" }, { "ÝŸŶΥΎΫỲỸỶỴЙ", "Y" }, { "ýÿŷỳỹỷỵй", "y" }, { "В", "V" }, { "в", "v" }, { "Ŵ", "W" }, { "ŵ", "w" }, { "ŹŻŽΖЗ", "Z" }, { "źżžζз", "z" }, { "ÆǼ", "AE" }, { "ß", "ss" }, { "IJ", "IJ" }, { "ij", "ij" }, { "Œ", "OE" }, { "ƒ", "f" }, { "ξ", "ks" }, { "π", "p" }, { "β", "v" }, { "μ", "m" }, { "ψ", "ps" }, { "Ё", "Yo" }, { "ё", "yo" }, { "Є", "Ye" }, { "є", "ye" }, { "Ї", "Yi" }, { "Ж", "Zh" }, { "ж", "zh" }, { "Х", "Kh" }, { "х", "kh" }, { "Ц", "Ts" }, { "ц", "ts" }, { "Ч", "Ch" }, { "ч", "ch" }, { "Ш", "Sh" }, { "ш", "sh" }, { "Щ", "Shch" }, { "щ", "shch" }, { "ЪъЬь", "" }, { "Ю", "Yu" }, { "ю", "yu" }, { "Я", "Ya" }, { "я", "ya" }, }; public static char RemoveDiacritics(this char c){ foreach(KeyValuePair<string, string> entry in foreign_characters) { if(entry.Key.IndexOf (c) != -1) { return entry.Value[0]; } } return c; } public static string RemoveDiacritics(this string s) { //StringBuilder sb = new StringBuilder (); string text = ""; foreach (char c in s) { int len = text.Length; foreach(KeyValuePair<string, string> entry in foreign_characters) { if(entry.Key.IndexOf (c) != -1) { text += entry.Value; break; } } if (len == text.Length) { text += c; } } return text; } }использование
// for strings "crème brûlée".RemoveDiacritics (); // creme brulee // for chars "Ã"[0].RemoveDiacritics (); // A
кодовая страница греческий (ISO) можете сделать это
информация об этой кодовой странице находится в
System.Text.Encoding.GetEncodings(). Узнайте об этом в: https://msdn.microsoft.com/pt-br/library/system.text.encodinginfo.getencoding(v=vs.110).aspxгреческий (ISO) имеет кодовую страницу 28597 и имя iso-8859-7.
перейти к коду... \o/
string text = "Você está numa situação lamentável"; string textEncode = System.Web.HttpUtility.UrlEncode(text, Encoding.GetEncoding("iso-8859-7")); //result: "Voce+esta+numa+situacao+lamentavel" string textDecode = System.Web.HttpUtility.UrlDecode(textEncode); //result: "Voce esta numa situacao lamentavel"Итак, напишите эту функцию...
public string RemoveAcentuation(string text) { return System.Web.HttpUtility.UrlDecode( System.Web.HttpUtility.UrlEncode( text, Encoding.GetEncoding("iso-8859-7"))); }обратите внимание, что...
Encoding.GetEncoding("iso-8859-7")эквивалентноEncoding.GetEncoding(28597)потому что во-первых это имя, а во-вторых кодовая страница кодирования.
Это прекрасно работает в Java.
он в основном преобразует все акцентированные символы в их деакцентированные аналоги с последующим их объединением диакритики. Теперь вы можете использовать регулярное выражение для удаления диакритических знаков.
import java.text.Normalizer; import java.util.regex.Pattern; public String deAccent(String str) { String nfdNormalizedString = Normalizer.normalize(str, Normalizer.Form.NFD); Pattern pattern = Pattern.compile("\p{InCombiningDiacriticalMarks}+"); return pattern.matcher(nfdNormalizedString).replaceAll(""); }
это версия VB (работает с греческим языком):
Система Импорта.Текст
Система Импорта.Глобализация
Public Function RemoveDiacritics(ByVal s As String) Dim normalizedString As String Dim stringBuilder As New StringBuilder normalizedString = s.Normalize(NormalizationForm.FormD) Dim i As Integer Dim c As Char For i = 0 To normalizedString.Length - 1 c = normalizedString(i) If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then stringBuilder.Append(c) End If Next Return stringBuilder.ToString() End Function
вот как я заменяю диакритические символы на недиакритические во всей моей программе .NET
C#:
//Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter 'é' is substituted by an 'e' public string RemoveDiacritics(string s) { string normalizedString = null; StringBuilder stringBuilder = new StringBuilder(); normalizedString = s.Normalize(NormalizationForm.FormD); int i = 0; char c = ''; for (i = 0; i <= normalizedString.Length - 1; i++) { c = normalizedString[i]; if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) { stringBuilder.Append(c); } } return stringBuilder.ToString().ToLower(); }VB .NET:
'Transforms the culture of a letter to its equivalent representation in the 0-127 ascii table, such as the letter "é" is substituted by an "e"' Public Function RemoveDiacritics(ByVal s As String) As String Dim normalizedString As String Dim stringBuilder As New StringBuilder normalizedString = s.Normalize(NormalizationForm.FormD) Dim i As Integer Dim c As Char For i = 0 To normalizedString.Length - 1 c = normalizedString(i) If CharUnicodeInfo.GetUnicodeCategory(c) <> UnicodeCategory.NonSpacingMark Then stringBuilder.Append(c) End If Next Return stringBuilder.ToString().ToLower() End Function
вы можете использовать расширение строки из MMLib.Расширения nuget пакет:
using MMLib.RapidPrototyping.Generators; public void ExtensionsExample() { string target = "aácčeéií"; Assert.AreEqual("aacceeii", target.RemoveDiacritics()); }
страница Nuget:https://www.nuget.org/packages/MMLib.Extensions/ Сайт проекта Codeplexhttps://mmlib.codeplex.com/
забавно, что такой вопрос может получить так много ответов, и все же ни один из них не соответствует моим требованиям :) вокруг так много языков, полное языковое агностическое решение AFAIK на самом деле невозможно, поскольку другие упоминали, что FormC или FormD дают проблемы.
поскольку исходный вопрос был связан с французским языком, самый простой рабочий ответ действительно
public static string ConvertWesternEuropeanToASCII(this string str) { return Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(str)); }1251 должен быть заменен кодом кодировки языка ввода.
однако это замените только один символ на один символ. Поскольку я также работаю с немецким языком в качестве ввода, я сделал ручное преобразование
public static string LatinizeGermanCharacters(this string str) { StringBuilder sb = new StringBuilder(str.Length); foreach (char c in str) { switch (c) { case 'ä': sb.Append("ae"); break; case 'ö': sb.Append("oe"); break; case 'ü': sb.Append("ue"); break; case 'Ä': sb.Append("Ae"); break; case 'Ö': sb.Append("Oe"); break; case 'Ü': sb.Append("Ue"); break; case 'ß': sb.Append("ss"); break; default: sb.Append(c); break; } } return sb.ToString(); }Это может не обеспечить лучшую производительность, но, по крайней мере, это очень легко читать и расширять. Регулярное выражение не идет, намного медленнее, чем любой материал char/string.
у меня также есть очень простой метод для удаления пространства:
public static string RemoveSpace(this string str) { return str.Replace(" ", string.Empty); }в конце концов, я использую комбинацию всех 3 выше расширения:
public static string LatinizeAndConvertToASCII(this string str, bool keepSpace = false) { str = str.LatinizeGermanCharacters().ConvertWesternEuropeanToASCII(); return keepSpace ? str : str.RemoveSpace(); }и небольшой модульный тест к тем (не исчерпывающим), которые проходят успешно.
[TestMethod()] public void LatinizeAndConvertToASCIITest() { string europeanStr = "Bonjour ça va? C'est l'été! Ich möchte ä Ä á à â ê é è ë Ë É ï Ï î í ì ó ò ô ö Ö Ü ü ù ú û Û ý Ý ç Ç ñ Ñ"; string expected = "Bonjourcava?C'estl'ete!IchmoechteaeAeaaaeeeeEEiIiiiooooeOeUeueuuuUyYcCnN"; string actual = europeanStr.LatinizeAndConvertToASCII(); Assert.AreEqual(expected, actual); }
попробовать HelperSharp package.
есть метод RemoveAccents:
public static string RemoveAccents(this string source) { //8 bit characters byte[] b = Encoding.GetEncoding(1251).GetBytes(source); // 7 bit characters string t = Encoding.ASCII.GetString(b); Regex re = new Regex("[^a-zA-Z0-9]=-_/"); string c = re.Replace(t, " "); return c; }
Imports System.Text Imports System.Globalization Public Function DECODE(ByVal x As String) As String Dim sb As New StringBuilder For Each c As Char In x.Normalize(NormalizationForm.FormD).Where(Function(a) CharUnicodeInfo.GetUnicodeCategory(a) <> UnicodeCategory.NonSpacingMark) sb.Append(c) Next Return sb.ToString() End Function
Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(text));он на самом деле разделяет подобных
åкоторый является одним символом (который является кодом символа00E5,не0061плюс модификатор030Aкоторый будет выглядеть так же) вaплюс какой-то модификатор, а затем преобразование ASCII удаляет модификатор, оставляя толькоa.
Мне очень нравится лаконичный и функциональный код azrafe7. Итак, я немного изменил его, чтобы преобразовать в метод расширения:
public static class StringExtensions { public static string RemoveDiacritics(this string text) { const string SINGLEBYTE_LATIN_ASCII_ENCODING = "ISO-8859-8"; if (string.IsNullOrEmpty(text)) { return string.Empty; } return Encoding.ASCII.GetString( Encoding.GetEncoding(SINGLEBYTE_LATIN_ASCII_ENCODING).GetBytes(text)); } }
выскакивает эта библиотека здесь, если вы еще не рассмотрели его. Похоже, что есть полный спектр модульных тестов с ним.
Comments