在C#(ascii)中替换字符

10

我有一个包含这些字符的文件:à,è,ì,ò,ù - À。我需要做的是用常规字符替换这些字符,例如:à = a,è = e等等...... 这是我目前的代码:

StreamWriter sw = new StreamWriter(@"C:/JoinerOutput.csv");
string path = @"C:/Joiner.csv";
string line = File.ReadAllText(path);

if (line.Contains("à"))
{
    string asAscii = Encoding.ASCII.GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(Encoding.ASCII.EncodingName, new EncoderReplacementFallback("a"), new DecoderExceptionFallback()), Encoding.UTF8.GetBytes(line)));
    Console.WriteLine(asAscii);
    Console.ReadLine();

    sw.WriteLine(asAscii);
    sw.Flush();
}

基本上,这个代码会在文件中搜索特定的字符并将其替换为另一个字符。我遇到的问题是我的if语句不起作用。我该如何解决呢?

以下是输入文件的示例:

Dimàkàtso Mokgàlo
Màmà Ràtlàdi
Koos Nèl
Pàsèkà Modisè
Jèrèmiàh Morèmi
Khèthiwè Buthèlèzi
Tiànà Pillày
Viviàn Màswàngànyè
Thirèshàn Rèddy
Wàdè Cornèlius
ènos Nètshimbupfè

如果使用以下代码: line = line.Replace('à', 'a'); 生成的输出结果如下:

Ch�rl�n� Kirst�n
M�m� R�tl�di
Koos N�l
P�s�k� Modis�
J�r�mi�h Mor�mi
Kh�thiw� Buth�l�zi
Ti�n� Pill�y
Vivi�n M�sw�ng�ny�
Thir�sh�n R�ddy
W�d� Corn�lius
�nos N�tshimbupf�

使用我的代码将完全删除该符号。


if语句有什么问题? - Fredrik Mörk
你的 if 语句不起作用是什么意思?它在字符串中找不到特定的字符吗? - Tejs
像à这样的字符有什么异常之处吗? - awm
OP必须是英语母语人士。对于许多语言来说,发音符号是必不可少的,但这在我们看来已经被忽略了。他的客户会强烈提醒他。 - Hans Passant
可能是Removing diacritics in Silverlight (String.Normalize issue)的重复问题。 - Hans Passant
7个回答

28

其他人已经评论过使用Unicode查找表来删除变音符号。我进行了一个快速的谷歌搜索,并找到了这个例子。代码无耻地抄袭(重新格式化),并在下面发布:

using System;
using System.Text;
using System.Globalization;

public static class Remove
{
    public static string RemoveDiacritics(string stIn)
    {
        string stFormD = stIn.Normalize(NormalizationForm.FormD);
        StringBuilder sb = new StringBuilder();

        for(int ich = 0; ich < stFormD.Length; ich++) {
            UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);
            if(uc != UnicodeCategory.NonSpacingMark) {
                sb.Append(stFormD[ich]);
            }
        }

        return(sb.ToString().Normalize(NormalizationForm.FormC));
    }
}

所以,你的代码可以通过调用以下方法来清理输入:

line = Remove.RemoveDiacritics(line);

11

不知道这是否有用,但在一个用于在LED屏幕上编写消息的内部工具中,我们有以下替换方式(我确信有更智能的方法来使Unicode表格正常工作,但对于这个小型内部工具而言,这已足够):

        strMessage = Regex.Replace(strMessage, "[éèëêð]", "e");
        strMessage = Regex.Replace(strMessage, "[ÉÈËÊ]", "E");
        strMessage = Regex.Replace(strMessage, "[àâä]", "a");
        strMessage = Regex.Replace(strMessage, "[ÀÁÂÃÄÅ]", "A");
        strMessage = Regex.Replace(strMessage, "[àáâãäå]", "a");
        strMessage = Regex.Replace(strMessage, "[ÙÚÛÜ]", "U");
        strMessage = Regex.Replace(strMessage, "[ùúûüµ]", "u");
        strMessage = Regex.Replace(strMessage, "[òóôõöø]", "o");
        strMessage = Regex.Replace(strMessage, "[ÒÓÔÕÖØ]", "O");
        strMessage = Regex.Replace(strMessage, "[ìíîï]", "i");
        strMessage = Regex.Replace(strMessage, "[ÌÍÎÏ]", "I");
        strMessage = Regex.Replace(strMessage, "[š]", "s");
        strMessage = Regex.Replace(strMessage, "[Š]", "S");
        strMessage = Regex.Replace(strMessage, "[ñ]", "n");
        strMessage = Regex.Replace(strMessage, "[Ñ]", "N");
        strMessage = Regex.Replace(strMessage, "[ç]", "c");
        strMessage = Regex.Replace(strMessage, "[Ç]", "C");
        strMessage = Regex.Replace(strMessage, "[ÿ]", "y");
        strMessage = Regex.Replace(strMessage, "[Ÿ]", "Y");
        strMessage = Regex.Replace(strMessage, "[ž]", "z");
        strMessage = Regex.Replace(strMessage, "[Ž]", "Z");
        strMessage = Regex.Replace(strMessage, "[Ð]", "D");
        strMessage = Regex.Replace(strMessage, "[œ]", "oe");
        strMessage = Regex.Replace(strMessage, "[Œ]", "Oe");
        strMessage = Regex.Replace(strMessage, "[«»\u201C\u201D\u201E\u201F\u2033\u2036]", "\"");
        strMessage = Regex.Replace(strMessage, "[\u2026]", "...");

需要注意的是,虽然在大多数语言中,经过此类处理后的文本仍然可读,但并不总是如此,而且往往会强迫读者参考上下文才能理解。如果有选择的话,这并不是你想要的。


请注意,正确的解决方法是使用Unicode表,用“组合变音符号+字符”形式替换带有整合变音符号的字符,然后去除变音符号...


看起来应该有更好的方法,但是使用C#内置方法似乎没有,所以我会收藏这个问题,以防将来需要借鉴这个答案。 :-) - Iain Collins
正确的解决方案是使用Unicode表,将带有整合变音符号的字符替换为它们的变音符号+字符形式,然后删除变音符号...但是,我目前在生产代码中没有这样做的需要,所以我也会收藏这个问题,以防有人做这个复杂的工作 :-) - Julien Roncaglia

7
我经常使用基于Dana提供的版本的扩展方法。 简单地解释一下:
  • 归一化成形式 D,可以将字符如 è 拆分为 e 和一个非间隔符 `
  • 从中删除无间隔字符
  • 结果再次归一化成形式 D(我不确定这是否必要)

代码:

using System.Linq;
using System.Text;
using System.Globalization;

// namespace here
public static class Utility
{
    public static string RemoveDiacritics(this string str)
    {
        if (str == null) 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;
    }
}

编辑

就像名字所说的一样,这只是去除变音符号,但这可能不是你想要的:

  • 在某些语言中,常见的做法是用字母组合替换带有变音符号的字符。例如,在德语中,ü被替换为ue。
  • 这只是根据Unicode定义去除变音符号。ö被视为o和̈的组合,但ø不被视为o和/的组合。 ł也是同样的情况。
  • 像œ和æ这样的组合字符也保持不变。

评论azrafe7在https://dev59.com/zXVC5IYBdhLWcg3wliGe的答案中,建议规范化解决方案存在问题。 - tymtam
@tymtam 谢谢,我已经将这些问题添加为免责声明/警告。 - realbart

3

为什么你要把事情搞得那么复杂?

line = line.Replace('à', 'a');

更新:

File.ReadAllText 的文档说明如下:

该方法尝试自动检测文件的编码方式,基于字节序标记的存在。可以检测到 UTF-8 和 UTF-32(大端和小端)编码格式。

在读取可能包含导入文本的文件时,请使用 ReadAllText(String, Encoding) 方法重载,因为无法识别的字符可能无法正确读取。

C:/Joiner.csv 文件采用什么编码方式?也许你应该使用另一种重载方法,为 File.ReadAllText 指定输入编码方式?


我本来也会这样回答,但我认为他试图避免为每个不想要的可能字符编写一组巨大的替换行。 =D - Tejs
1
@Tejs:就这一点而言,发布的代码肯定不比这个建议更好。里面有一个普通的和一个带重音的 a - Jon
如果我使用那段代码,这是输出的示例:Thir�sh�n R�ddy。 - Trishen
@Trishen:请编辑您的答案并发布所有相关代码,以便我们可以看到那是什么的输出。 - Jon
我已按要求编辑了问题,请看一下并告诉我您的想法。 - Trishen

2

简单易行的方法。以下代码只需两行即可将所有特殊字符替换为ASCII字符。它会给你与Julien Roncaglia解决方案相同的结果。

byte[] bytes = System.Text.Encoding.GetEncoding("Cyrillic").GetBytes(inputText);
string outputText = System.Text.Encoding.ASCII.GetString(bytes);

0
使用这个:
     if (line.Contains(“OldChar”))
     {
        line = line.Replace(“OldChar”, “NewChar”);
     }

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接