如何在C#中从字符串中删除非ASCII字符?

279

如何从字符串中剔除非ASCII字符?(使用C#)


7
根据 sinelaw 的答案(在下面),如果你想要 替换 非 ASCII 字符,**请查看 这个答案**。 - Bobson
17个回答

490
string s = "søme string";
s = Regex.Replace(s, @"[^\u0000-\u007F]+", string.Empty);

^是非运算符,它告诉正则表达式查找与之不匹配的所有内容而不是匹配的内容。 \u####-\u####表示哪些字符匹配。 \u0000-\u007F等同于utf-8或unicode中的前128个字符,它们总是ASCII字符。因此,你可以匹配每个非ASCII字符(由于非运算符),并对所有匹配项进行替换。

(如Gordon Tucker于2009年12月11日21:11在评论中解释的那样)


59
可打印字符的范围是0020-007E,对于寻找替换非打印字符的正则表达式的人来说,这一点很重要。 - Mubashar
如果您想查看ASCII字符集的表格,请访问:http://www.asciitable.com/ - scradam
扩展ASCII的范围是\u0000-\u00FF,适用于寻找正则表达式以替换非扩展ASCII字符的人(例如用于西班牙语应用程序中的变音符等...) - full_prog_full
4
@GordonTucker \u0000-\u007F 是 utf-8 或 unicode 的前127个字符,而不是前225个。请参考表格 - full_prog_full
4
这就是为什么我在大约一分钟后回复了自己,纠正自己说的是127而不是255。 :) - Gordon Tucker
显示剩余2条评论

159

这里是一个纯.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字符转换为空字符串。


8
太好了!我使用这个来清理一个字符串,然后保存到 RTF 文档中。非常感谢。比正则表达式版本容易理解多了。 - Nathan Prather
24
你真的觉得这样更容易理解吗?对我来说,那些不太相关的东西(回退、转换为字节等)会让人分心,远离实际发生的事情。 - bzlm
10
@Brandon,实际上,这种技术并没有比其他技术更好地完成任务。所以这个类比就是用一个普通的螺丝刀来代替一个花哨的iScrewDriver Deluxe 2000 :) - bzlm
16
一个优点是我可以轻松将ASCII替换为ISO 8859-1或其他编码 :) - Akira Yamamoto
1
@RageCompex,EncoderReplacementFallback并不是为转换而设计的。但是,您可以使用.NET的Unicode规范化和规范化API来实现您想要的功能。 - bzlm
显示剩余7条评论

62

我相信MonsCamus的意思是:

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

7
我认为这个答案比被采纳的答案更好,因为它去掉了控制字符。 - Dean2690

18

1
我甚至没有意识到这是可能的,但对我来说这是一个更好的解决方案。我将在问题的评论中添加此链接,以便其他人更容易找到。谢谢! - Bobson

13

在受到philcruz的正则表达式解决方案启发下,我写了一个纯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();
}

这是未经测试的代码。


7
可以考虑将单独的ToText()方法替换为以下代码,以更新PureAscii()方法的第三行:return new string(source.Select(c => c < min ? nil : c > max ? nil : c).ToArray())。这样做不会改变原意,同时让语言更通俗易懂。 - agentnega
或者将ToText写成:return (new string(source)).ToArray() - 取决于哪个更有效率。将ToText作为扩展方法仍然很好 - 流畅/管道式风格。 :-) - Bent Rasmussen
那段代码将非ASCII字符替换为空格。若要去除它们,请将Select更改为Where:return new string(source.Where(c => c >= min && c <= max).ToArray()); - Foozinator
@Foozinator 这段代码允许你指定用哪个字符来替换非ASCII字符。默认情况下,它使用空格,但如果像这样调用 .PureASCII(Char.MinValue),它将使用 '\0' 替换所有非ASCII字符,这仍然不完全是剥离它们,但结果类似。 - Ulfius
ToText方法可以被删除,第5行可以替换为:return source.Where(c => c >= min && c <= max).Aggregate(new StringBuilder(), (sb, s) => sb.Append(s), sb => sb.ToString()); - Joakim M. H.

5
我来到这里寻找扩展ASCII字符的解决方案,但未能找到。我找到的最接近的是bzlm的解决方案。但它仅适用于ASCII码127及以下(显然,您可以在他的代码中替换编码类型,但我认为这有点难以理解。因此,分享这个版本)。下面是一个解决方案,适用于扩展ASCII码,即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:

这里有一个工作的代码示例

根据要求替换编码,其余部分保持不变。


3
只有这个方法能够从字符串 "Ω c ç ã" 中仅移除 Ω。非常感谢! - Rafael Araújo

5
我发现以下略有改动的范围对于从数据库解析注释块非常有用,这意味着您不必处理制表符和转义字符,这会导致CSV字段变得混乱。
parsememo = Regex.Replace(parsememo, @"[^\u001F-\u007F]", string.Empty);

如果你想避免其他特殊字符或特定标点符号,请查看ascii表


1
如果有人没有注意到其他评论,可打印字符实际上是 @"[^\u0020-\u007E]"。如果你好奇,这里有一个链接可以看到表格:http://www.asciitable.com/。 - scradam

5
不需要使用正则表达式,只需使用编码...
sOutput = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.ASCII.GetBytes(sInput));

7
无效。这并不会去除Unicode字符,而是用“?”替换它们。 - David
1
@David是正确的。当我在mono 3.4中尝试输入“たまねこnachoなち”时,至少我得到了????nacho?? - nacho4d
2
你可以实例化自己的编码类,而不是替换字符,而是删除它们。请参阅 GetEncoding 方法:https://msdn.microsoft.com/zh-cn/library/89856k4b(v=vs.110).aspx - kkara

3
这种方法在性能方面并不是最佳的选择,但它是一种相当直接的 Linq 方法:
string strippedString = new string(
    yourString.Where(c => c <= sbyte.MaxValue).ToArray()
    );

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

1
我使用这个正则表达式来过滤文件名中的不良字符。
Regex.Replace(directory, "[^a-zA-Z0-9\\:_\- ]", "")

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

3
不行。请参考 Path.GetInvalidPathCharsPath.GetInvalidFileNameChars。因此,有成千上万个有效字符。 - Tom Blodget
你说得对,汤姆。我实际上是在考虑常见的符号,但是我忘记了括号、花括号以及所有这些 - ^%$#@!&+=。 - user890332

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