如何从字符串中去除非 ASCII 字符? (在 C# 中)

Posted

技术标签:

【中文标题】如何从字符串中去除非 ASCII 字符? (在 C# 中)【英文标题】:How can you strip non-ASCII characters from a string? (in C#) 【发布时间】:2010-09-12 12:10:21 【问题描述】:

【问题讨论】:

根据 sinelaw 的回答 below,如果您想替换非 ASCII 字符,请参阅 this answer 【参考方案1】:
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);

【讨论】:

对于我们这些受到 RegEx 挑战的人,您介意用简单的英语写出您的 RegEx 模式吗?换句话说,“^ 做这个”等等...... @Metro Smurf ^ 是非运算符。它告诉正则表达式查找不匹配的所有内容,而不是匹配的所有内容。 \u####-\u#### 表示匹配的字符。\u0000-\u007F 是 utf-8 或 unicode 中的前 255 个字符的等价物,它们始终是 ascii 字符。因此,您匹配每个非 ascii 字符(因为不是)并对匹配的所有内容进行替换。 可打印字符的范围是 0020-007E,供寻找正则表达式替换不可打印字符的人使用 @GordonTucker \u0000-\u007F 等同于 utf-8 或 unicode 中的 前 127 个字符,而不是前 225。请参阅 table @full_prog_full 这就是为什么我在一分钟后回复自己,纠正自己说是 127 而不是 255。:)【参考方案2】:

这是一个不使用正则表达式的纯 .NET 解决方案:

string inputString = "Räksmörgås";
string asAscii = Encoding.ASCII.GetString(
    Encoding.Convert(
        Encoding.UTF8,
        Encoding.GetEncoding(
            Encoding.ASCII.EncodingName,
            new EncoderReplacementFallback(string.Empty),
            new DecoderExceptionFallback()
            ),
        Encoding.UTF8.GetBytes(inputString)
    )
);

它可能看起来很麻烦,但它应该是直观的。它使用 .NET ASCII 编码来转换字符串。在转换过程中使用 UTF8,因为它可以表示任何原始字符。它使用 EncoderReplacementFallback 将任何非 ASCII 字符转换为空字符串。

【讨论】:

完美!在将字符串保存到 RTF 文档之前,我使用它来清理字符串。非常感谢。比 Regex 版本更容易理解。 你真的觉得它更容易理解吗?对我来说,所有不相关的东西(回退、转换为字节等)都在将注意力从实际发生的事情上转移开。 @Brandon,实际上,这种技术并不比其他技术做得更好。所以类比是使用普通的老式螺丝刀而不是花哨的 iScrewDriver Deluxe 2000。:) @bzim 这就像在螺丝上使用锤子:) 好的,不。这就像使用汽车发动机的曲轴来驱动螺丝一样。我们开始了。 一个优点是我可以轻松地将 ASCII 替换为 ISO 8859-1 或其他编码:)【参考方案3】:

受philcruz's Regular Expression solution的启发,我做了一个纯LINQ解决方案

public static string PureAscii(this string source, char nil = ' ')

    var min = '\u0000';
    var max = '\u007F';
    return source.Select(c => c < min ? nil : c > max ? nil : c).ToText();


public static string ToText(this IEnumerable<char> source)

    var buffer = new StringBuilder();
    foreach (var c in source)
        buffer.Append(c);
    return buffer.ToString();

这是未经测试的代码。

【讨论】:

对于那些没有抓住它的人来说,这是一个基于 C# 4.0 LINQ 的解决方案。 :) 代替单独的 ToText() 方法,如何将 PureAscii() 的第 3 行替换为: return new string(source.Select(c => c max ? nil : c).ToArray()); 或者 ToText 为:return (new string(source)).ToArray() - 取决于什么表现最好。将 ToText 作为扩展方法仍然很好 - 流利/管道样式。 :-) 该代码将非 ASCII 字符替换为空格。要删除它们,请将 Select 更改为 Where:return new string( source.Where( c =&gt; c &gt;= min &amp;&amp; c &lt;= max ).ToArray() ); @Foozinator 该代码允许您指定用哪个字符替换非 ASCII 字符。默认情况下它使用一个空格,但如果它被称为 .PureASCII(Char.MinValue),它会将所有非 ASCII 替换为 '\0' - 这仍然不是完全剥离它们,但结果相似。【参考方案4】:

如果您不想剥离,而是要将带有重音的拉丁字符实际转换为非重音字符,请查看以下问题:How do I translate 8bit characters into 7bit characters? (i.e. Ü to U)

【讨论】:

我什至没有意识到这是可能的,但这对我来说是一个更好的解决方案。我将将此链接添加到对该问题的评论中,以便其他人更容易找到。谢谢!【参考方案5】:

我使用了这个正则表达式:

    string s = "søme string";
    Regex regex = new Regex(@"[^a-zA-Z0-9\s]", (RegexOptions)0);
    return regex.Replace(s, "");

【讨论】:

这也会删除标点符号,以防万一这不是某人想要的。【参考方案6】:

我发现以下稍微更改的范围对于从数据库中解析注释块很有用,这意味着您不必与制表符和转义符抗衡,因为这会导致 CSV 字段变得混乱。

parsememo = Regex.Replace(parsememo, @"[^\u001F-\u007F]", string.Empty);

如果要避免其他特殊字符或特定标点符号检查the ascii table

【讨论】:

如果有人没有注意到其他 cmets,可打印的字符实际上是 @"[^\u0020-\u007E]"。如果您好奇,可以通过以下链接查看表格:asciitable.com【参考方案7】:

不需要正则表达式。只需使用编码...

sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));

【讨论】:

这不起作用。这不会去除 unicode 字符,而是将它们替换为 ?字符。 @David 是对的。至少我在尝试时得到了????nacho??たまねこnachoなち in mono 3.4 您可以实例化自己的 Encoding 类,而不是替换字符,而是删除它们。见GetEncoding方法:msdn.microsoft.com/en-us/library/89856k4b(v=vs.110).aspx【参考方案8】:

我相信 MonsCamus 的意思是:

parsememo = Regex.Replace(parsememo, @"[^\u0020-\u007E]", string.Empty);

【讨论】:

恕我直言,这个答案比公认的答案更好,因为它去掉了控制字符。【参考方案9】:

这不是最佳的性能,而是一种非常直接的 Linq 方法:

string strippedString = new string(
    yourString.Where(c => c <= sbyte.MaxValue).ToArray()
    );

缺点是所有“幸存的”字符首先放入char[] 类型的数组中,然后在string 构造函数不再使用它之后将其丢弃。

【讨论】:

【参考方案10】:

我来这里寻找扩展 ascii 字符的解决方案,但找不到。我找到的最接近的是bzlm's solution。但这仅适用于最高 127 的 ASCII 代码(显然您可以替换他代码中的编码类型,但我认为理解起来有点复杂。因此,分享这个版本)。这是适用于extended ASCII codes i.e. upto 255 的解决方案,即ISO 8859-1

它发现并去除非ascii字符(大于255)

Dim str1 as String= "â, ??î or ôu?� n☁i✑?++$-?♓!???‼⁉4⃣od;/⏬'®;?☕?:☝)??///?1!@#"

Dim extendedAscii As Encoding = Encoding.GetEncoding("ISO-8859-1", 
                                                New EncoderReplacementFallback(String.empty),
                                                New DecoderReplacementFallback())

Dim extendedAsciiBytes() As Byte = extendedAscii.GetBytes(str1)

Dim str2 As String = extendedAscii.GetString(extendedAsciiBytes)

console.WriteLine(str2)
'Output : â, ??î or ôu ni++$-!‼⁉4od;/';:)///1!@#$%^yz:

这是working fiddle for the code

按要求替换编码,其余保持不变。

【讨论】:

唯一一个仅从该字符串“Ω c çã”中删除Ω的方法。非常感谢!【参考方案11】:

我使用这个正则表达式过滤掉文件名中的坏字符。

Regex.Replace(directory, "[^a-zA-Z0-9\\:_\- ]", "")

这应该是文件名允许的所有字符。

【讨论】:

不。请参阅 Path.GetInvalidPathChars 和 Path.GetInvalidFileNameChars。因此,有数万个有效字符。 你是对的,汤姆。我实际上是在考虑常见的,但我忽略了括号和花括号以及所有这些 - ^%$#@!&+=。【参考方案12】:

亡灵术。 此外,bzlm 的方法可用于删除不在任意字符集中的字符,而不仅仅是 ASCII:

// https://en.wikipedia.org/wiki/Code_page#EBCDIC-based_code_pages
// https://en.wikipedia.org/wiki/Windows_code_page#East_Asian_multi-byte_code_pages
// https://en.wikipedia.org/wiki/Chinese_character_encoding
System.Text.Encoding encRemoveAllBut = System.Text.Encoding.ASCII;
encRemoveAllBut = System.Text.Encoding.GetEncoding(System.Globalization.CultureInfo.InstalledUICulture.TextInfo.ANSICodePage); // System-encoding
encRemoveAllBut = System.Text.Encoding.GetEncoding(1252); // Western European (iso-8859-1)
encRemoveAllBut = System.Text.Encoding.GetEncoding(1251); // Windows-1251/KOI8-R
encRemoveAllBut = System.Text.Encoding.GetEncoding("ISO-8859-5"); // used by less than 0.1% of websites
encRemoveAllBut = System.Text.Encoding.GetEncoding(37); // IBM EBCDIC US-Canada
encRemoveAllBut = System.Text.Encoding.GetEncoding(500); // IBM EBCDIC Latin 1
encRemoveAllBut = System.Text.Encoding.GetEncoding(936); // Chinese Simplified
encRemoveAllBut = System.Text.Encoding.GetEncoding(950); // Chinese Traditional
encRemoveAllBut = System.Text.Encoding.ASCII; // putting ASCII again, as to answer the question 

// https://***.com/questions/123336/how-can-you-strip-non-ascii-characters-from-a-string-in-c
string inputString = "RäksmörПривет, мирgås";
string asAscii = encRemoveAllBut.GetString(
    System.Text.Encoding.Convert(
        System.Text.Encoding.UTF8,
        System.Text.Encoding.GetEncoding(
            encRemoveAllBut.CodePage,
            new System.Text.EncoderReplacementFallback(string.Empty),
            new System.Text.DecoderExceptionFallback()
            ),
        System.Text.Encoding.UTF8.GetBytes(inputString)
    )
);

System.Console.WriteLine(asAscii);

对于那些只想消除口音的人: (注意,因为 Normalize != Latinize != Romanize)

// string str = Latinize("(æøå âôû?aè");
public static string Latinize(string stIn)

    // Special treatment for German Umlauts
    stIn = stIn.Replace("ä", "ae");
    stIn = stIn.Replace("ö", "oe");
    stIn = stIn.Replace("ü", "ue");

    stIn = stIn.Replace("Ä", "Ae");
    stIn = stIn.Replace("Ö", "Oe");
    stIn = stIn.Replace("Ü", "Ue");
    // End special treatment for German Umlauts

    string stFormD = stIn.Normalize(System.Text.NormalizationForm.FormD);
    System.Text.StringBuilder sb = new System.Text.StringBuilder();

    for (int ich = 0; ich < stFormD.Length; ich++)
    
        System.Globalization.UnicodeCategory uc = System.Globalization.CharUnicodeInfo.GetUnicodeCategory(stFormD[ich]);

        if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)
        
            sb.Append(stFormD[ich]);
         // End if (uc != System.Globalization.UnicodeCategory.NonSpacingMark)

     // Next ich


    //return (sb.ToString().Normalize(System.Text.NormalizationForm.FormC));
    return (sb.ToString().Normalize(System.Text.NormalizationForm.FormKC));
 // End Function Latinize

【讨论】:

以上是关于如何从字符串中去除非 ASCII 字符? (在 C# 中)的主要内容,如果未能解决你的问题,请参考以下文章

从 NSString 中去除非字母数字字符

从 Snowflake 中的字符串中删除非 ASCII 字符

在 Oracle SQL 中去除非英文字符

c语言编程中如何显示字符的ASCII码值?

字符型数据在内存中是以啥形式存放的

c中如何输出一个字符的ASCII码