当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何从.NET中的字符串中删除变音符号(重音符号)?》经验,为你挑选了8个好方法。

我正在尝试转换一些法语加拿大语的字符串,基本上,我希望能够在保留字母的同时取出字母中的法语重音符号.(例如转换ée,所以crème brûlée会变成creme brulee)

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



1> Blair Conrad..:

我没有使用过这种方法,但迈克尔·卡普兰在他的博客文章(带有令人困惑的标题)中描述了这样做的方法,该文章讨论剥离变音符号:剥离是一项有趣的工作(又名无意义的意思,又名所有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);
}

请注意,这是他早期帖子的后续内容:剥离变音符....

该方法使用String.Normalize将输入字符串拆分为组成字形(基本上将"基本"字符与变音符号分开),然后扫描结果并仅保留基本字符.这有点复杂,但实际上你正在研究一个复杂的问题.

当然,如果你限制自己使用法语,你可能会按照@David Dibben的建议,在如何删除C++ std :: string中的重音符号和波形符号中使用简单的基于表格的方法.


这是错的.德国人物ä和ö和ü被认为是ae和la,而不是ou ...
@StefanSteiger你知道,在捷克有一些像áčěů这样的字母,我们通常会把它"拉"到aceu,即使它听起来不同,可能会引起像"hrábě"/ hra:bje /,"hrabě"/ hrabje /这样的混淆,和"hrabe"/ hrabe /.对我而言,删除变音符号似乎是一个纯粹的图形问题,与信件的语音或历史无关.像äöü这样的字母是通过在基本字母上添加上标"e"而创建的,因此"ae"分解在历史上是有意义的.这取决于目标 - 删除图形标记,或将字母分解为ASCII字符.
此外,波兰语字母ł被忽略.
此功能与语言无关.它不知道字符串是德语还是其他语言.如果我们考虑到在德语文本中用oe替换ö是可以的,但是用土耳其语做它没有任何意义,那么我们会发现在没有检测到语言的情况下这个问题实际上是不可解决的.
Norseø也被忽略了
所以,这个解决方案不适用于挪威ø,波兰语ł,土耳其语,阿塞拜疆语等.基本上,对于任何没有可分离变音符号的字母.
别忘了添加`using System; 使用System.Globalization; 使用System.Text; 使用System.Text.RegularExpressions;`
我不认为目标是拥有一种完美的书写方式,而是拥有可以在大多数应用程序中使用的功能。我将其用于自动化,主要用于创建帐户以及带有重音和怪异字符的名称。Active Directory和许多应用程序不能很好地吸收这些字符,因此在创建任何帐户时,我将它们规范化为某个名称,例如对于帐户名称,其名称将更“普通”。

2> 小智..:

这对我有用...

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

快速和短暂!


这是我见过的最好的方法.
请记住,用`?`取代`ß`会很奇怪.
我喜欢这个解决方案,它适用于Windows应用商店应用.但是,它不适用于Windows Phone应用程序,因为编码ISO-8859-8似乎不可用.是否可以使用其他编码?
这适用于大多数常见字符,但许多特殊字符如``````和`...`(作为单个字符)将在过程中被改变,而接受的解决方案则不然.

3> Luk..:

如果有人感兴趣,我正在寻找类似的东西并结束了以下内容:

    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
    }


您应该将StringBuilder缓冲区预先分配给name.Length以最小化内存分配开销.删除顺序重复_的最后一次拆分/加入调用很有意思.也许我们应该避免在循环中添加它们.设置前一个字符为_的标志,如果为true,则不发出一个标志.

4> CIRCLE..:

我需要一些可以转换所有主要unicode字符的东西,并且投票的答案留了一些,所以我在convert_accented_characters($str)C#中创建了一个可以轻松定制的CodeIgniter版本:

using System;
using System.Text;
using System.Collections.Generic;

public static class Strings
{
    static Dictionary foreign_characters = new Dictionary
    {
        { "äæ?", "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" },
        { "ÒÓÔÕ?????Ø??????????????????", "O" },
        { "òóôõ?????ø?º?????????????????", "o" },
        { "?", "P" },
        { "?", "p" },
        { "?????", "R" },
        { "?????", "r" },
        { "????Š??", "S" },
        { "????š????", "s" },
        { "??????", "T" },
        { "?????", "t" },
        { "ÙÚÛ?????????????????????", "U" },
        { "ùúû???????????????????????", "u" },
        { "ÝŸ?????????", "Y" },
        { "ýÿ??????", "y" },
        { "?", "V" },
        { "?", "v" },
        { "?", "W" },
        { "?", "w" },
        { "??Ž??", "Z" },
        { "??ž??", "z" },
        { "Æ?", "AE" },
        { "ß", "ss" },
        { "?", "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 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 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


https://github.com/apache/lucenenet/blob/master/src/Lucene.Net.Analysis.Common/Analysis/Miscellaneous/ASCIIFoldingFilter.cs
您的实现可以完成这项工作,但在生产代码中使用之前应该进行改进.

5> KenE..:

如果有人感兴趣,这里是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.charAt(i)使用StringBuilder.你在这里隐藏了O(n²)运行时.
这里的这个和其他Java答案只是弄乱了这个线程。问题是关于c#(.NET)而不是Java!

6> realbart..:

我经常使用基于我在这里找到的另一个版本的扩展方法(请参阅替换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> Sergio Cabra..:

希腊语(ISO)的CodePage 可以做到这一点

有关此代码页的信息是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)因为first是名称,第二个是Encoding的代码页.


太精彩了!简短而有效!

8> EricBDev..:

有趣的是,这样一个问题可以得到这么多答案,但又没有一个适合我的要求:)周围有太多语言,一种完全与语言无关的解决方案真的不可能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);
    }

最终,我使用了以上所有三个扩展的组合:

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

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有