代码之家  ›  专栏  ›  技术社区  ›  James Hall

如何从.NET中的字符串中删除音调符号(重音符号)?

  •  372
  • James Hall  · 技术社区  · 17 年前

    我正在尝试转换一些加拿大法文的字符串,基本上,我希望能够在保留字母的同时去掉字母中的法国重音符号。(例如转换) é e 如此 crème brûlée 将成为 creme brulee )

    实现这一目标的最佳方法是什么?

    17 回复  |  直到 8 年前
        1
  •  459
  •   Ry- Vincenzo Alcamo    9 年前

    我没有使用过这种方法,但是Michael Kaplan在他的博客文章(标题令人费解)中描述了一种去除发音符号的方法: Stripping is an interesting job (aka On the meaning of meaningless, aka All Mn characters are non-spacing, but some are more non-spacing than others)

    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);
    }
    

    请注意,这是他之前的帖子的后续内容: Stripping diacritics....

    该方法使用 String.Normalize 要将输入字符串拆分为组成glyph(基本上将“基础”字符与音调符号分离),然后扫描结果并仅保留基础字符。这只是有点复杂,但实际上你在看一个复杂的问题。

    当然,如果您将自己限制在法语,那么您可能可以在 How to remove accents and tilde in a C++ std::string ,根据@david dibben的建议。

        2
  •  134
  •   azrafe7    16 年前

    这对我有好处…

    string accentedStr;
    byte[] tempBytes;
    tempBytes = System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(accentedStr);
    string asciiStr = System.Text.Encoding.UTF8.GetString(tempBytes);
    

    快&短!

        3
  •  28
  •   Luk    17 年前

    如果有人感兴趣,我会找类似的东西,然后写下以下内容:

        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
        }
    
        4
  •  15
  •   KenE    16 年前

    如果有人感兴趣,这里是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();
        }
    }
    
        5
  •  15
  •   CIRCLE    10 年前

    我需要一些东西来转换所有主要的Unicode字符,投票的答案会留下一些,所以我创建了一个版本的codeigner'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
    
        6
  •  12
  •   realbart    8 年前

    我经常使用基于我在这里找到的另一个版本的扩展方法 (见 Replacing characters in C# (ascii) ) 快速解释:

    • 规范化为D形拆分 γ e 还有一个不停的 `
    • 从中删除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);
        }
    }
    
        7
  •  8
  •   Sergio Cabral    10 年前

    CodePage 希腊语(ISO) 能做到

    有关此代码页的信息 System.Text.Encoding.GetEncodings() . 了解在: https://msdn.microsoft.com/pt-br/library/system.text.encodinginfo.getencoding(v=vs.110).aspx

    希腊语(ISO)有代码页 二万八千五百九十七 和名字 ISO-855-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) 因为第一个是名称,第二个是编码的代码页。

        8
  •  4
  •   hashable    17 年前

    这在Java中很好用。

    它基本上将所有重音字符转换为它们的不发音对应词,然后再组合音调符号。现在可以使用regex去掉音调符号。

    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("");
    }
    
        9
  •  3
  •   Stefanos Michanetzis    16 年前

    这是vb版本(与希腊语一起使用):

    导入System.Text

    进口系统.全球化

    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
    
        10
  •  3
  •   EricBDev    9 年前

    有趣的是,这样一个问题能得到如此多的答案,但没有一个符合我的要求:)周围有如此多的语言,一个完整的语言不可知论解决方案是不可能的,因为其他人已经提到,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();
        }
    

    它可能无法提供最佳性能,但至少非常容易阅读和扩展。 regex是一个禁忌,比任何char/string东西都慢得多。

    我还有一个非常简单的方法来删除空间:

        public static string RemoveSpace(this string str)
        {
            return str.Replace(" ", string.Empty);
        }
    

    最后,我将使用上述三种扩展的组合:

        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);
        }
    
        11
  •  2
  •   Heyjee    13 年前

    这就是我如何在所有.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 = '\0';
    
        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
    
        12
  •  2
  •   Mino    12 年前

    可以使用mmlib.extensions 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/ codeplex项目站点 https://mmlib.codeplex.com/

        13
  •  1
  •   giacomelli    13 年前

    尝试 HelperSharp package .

    有一个方法移除:

     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;
     }
    
        14
  •  1
  •   Tratak    11 年前
    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
    
        15
  •  1
  •   Community Mohan Dere    9 年前

    What this person said:

    Encoding.ASCII.GetString(Encoding.GetEncoding(1251).GetBytes(text));

    它实际上可以分割 Ã¥ 一个字符(字符代码 00E5 , 0061 加上修饰语 030A 看起来是一样的) a 加上某种修饰符,然后ASCII转换将删除修饰符,只保留 .

        16
  •  0
  •   Community Mohan Dere    9 年前

    我真的很喜欢由 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));
        }
    }
    
        17
  •  0
  •   Squiggs.    9 年前

    如果你还没有考虑过,就把这个图书馆放在这里。看起来有一个完整的单元测试。

    https://github.com/thomasgalliker/Diacritics.NET

    推荐文章