43

我的问题:

我有一个 .NET 应用程序,它通过电子邮件发送时事通讯。在 Outlook 中查看时事通讯时,Outlook 会显示一个问号来代替它无法识别的隐藏字符。这些隐藏字符来自最终用户,他们将组成时事通讯的 html 复制并粘贴到表单中并提交。如果这些隐藏字符出现在字符串的末尾或开头,则 c# trim() 会删除它们。当在 gmail 中查看时事通讯时,gmail 可以很好地忽略它们。将这些隐藏字符粘贴到 Word 文档中并打开“显示段落标记和隐藏符号”选项时,符号显示为一个更大矩形内的一个矩形。此外,组成时事通讯的文本可以是任何语言,因此必须接受 Unicode 字符。一世' 我尝试循环遍历字符串以检测字符,但循环无法识别它并通过它。还要求最终用户在提交之前先将 html 粘贴到记事本中是不可能的。

我的问题:
如何使用 C# 检测和消除这些隐藏字符?

4

8 回答 8

93

您可以使用以下内容从输入字符串中删除所有控制字符:

string input; // this is your input string
string output = new string(input.Where(c => !char.IsControl(c)).ToArray());

这是该方法的文档IsControl()

或者如果你只想保留字母和数字,你也可以使用IsLetterandIsDigit函数:

string output = new string(input.Where(c => char.IsLetter(c) || char.IsDigit(c)).ToArray());
于 2013-03-06T22:27:21.190 回答
28

我通常使用这个正则表达式来替换所有不可打印的字符。

顺便说一句,大多数人认为制表符、换行符和回车符是不可打印的字符,但对我来说不是。

所以这里是表达式:

string output = Regex.Replace(input, @"[^\u0009\u000A\u000D\u0020-\u007E]", "*");
  • ^表示如果它是以下任何一种:
  • \u0009是标签
  • \u000A是换行
  • \u000D是回车
  • \u0020-\u007E表示从空间到的所有内容~——即 ASCII 中的所有内容。

如果要进行更改,请参阅ASCII 表。请记住,它会删除每个非 ASCII 字符。

要在上面进行测试,您可以自己创建一个字符串,如下所示:

    string input = string.Empty;

    for (int i = 0; i < 255; i++)
    {
        input += (char)(i);
    }
于 2014-02-17T05:27:25.110 回答
7

最适合我的是:

string result = new string(value.Where(c =>  char.IsLetterOrDigit(c) || (c >= ' ' && c <= byte.MaxValue)).ToArray());

在我确保字符是任何字母或数字的地方,这样我就不会忽略任何非英文字母,或者如果它不是字母,我会检查它是否是大于或等于空格的 ascii 字符以确保我忽略了一些控制字符,这样可以确保我不会忽略标点符号。

有些人建议使用 IsControl 来检查字符是否不可打印,但例如忽略从左到右标记。

于 2016-11-30T12:30:32.823 回答
7
new string(input.Where(c => !char.IsControl(c)).ToArray());

IsControl 遗漏了一些控制字符,例如从左到右标记 (LRM)(在进行复制粘贴时通常隐藏在字符串中的字符)。如果您确定您的字符串只有数字和数字,那么您可以使用 IsLetterOrDigit

new string(input.Where(c => char.IsLetterOrDigit(c)).ToArray())

如果你的字符串有特殊字符,那么

new string(input.Where(c => c < 128).ToArray())
于 2017-03-15T00:27:46.727 回答
4

你可以这样做:

var hChars = new char[] {...};
var result = new string(yourString.Where(c => !hChars.Contains(c)).ToArray());
于 2013-03-06T22:27:52.473 回答
1

TLDR 答案

使用这个正则表达式...

\P{Cc}\P{Cn}\P{Cs}

像这样...

var regex = new Regex(@"![\P{Cc}\P{Cn}\P{Cs}]");

TLDR 解释

  • \P{Cc}:匹配控制字符。
  • \P{Cn}匹配未分配的字符。
  • \P{Cs}:匹配 UTF-8 无效字符。

工作演示

在这个演示中,我使用这个正则表达式来搜索字符串"Hello, World!"。最后那个奇怪的字符是(char)4——这是END TRANSMISSION.

using System;
using System.Text.RegularExpressions;

public class Test {
    public static void Main() {
        var regex = new Regex(@"![\P{Cc}\P{Cn}\P{Cs}]");
        var matches = regex.Matches("Hello, World!" + (char)4);
        Console.WriteLine("Results: " + matches.Count);
        foreach (Match match in matches) {
            Console.WriteLine("Result: " + match);
        }
    }
}

IDEOne.com 上的完整工作演示

上述代码的输出:

Results: 1
Result: !

备择方案

  • \P{C}: 只匹配可见字符。不要匹配任何不可见的字符。
  • \P{Cc}: 只匹配非控制字符。不匹配任何控制字符。
  • \P{Cc}\P{Cn}:仅匹配已分配的非控制字符。不要匹配任何控制或未分配的字符。
  • \P{Cc}\P{Cn}\P{Cs}:仅匹配已分配且 UTF-8 有效的非控制字符。不匹配任何控制、未分配或 UTF-8 无效字符。
  • \P{Cc}\P{Cn}\P{Cs}\P{Cf}:仅匹配已分配且 UTF-8 有效的非控制、非格式字符。不匹配任何控制、未分配、格式化或 UTF-8 无效字符。

来源和解释

查看可用于在正则表达式中进行测试的Unicode 字符属性。您应该能够在Microsoft .NETJavaScriptPythonJavaPHPRubyPerlGolang甚至Adob ​​e 中使用这些正则表达式。了解 Unicode 字符类是非常可转移的知识,所以我推荐使用它!

于 2021-06-30T15:16:32.963 回答
0

我使用这个快速而肮脏的 oneliner 从损坏的 Windows 10 计算器应用程序留下的 LTR/RTL 标记中清除了一些输入。这可能与完美相去甚远,但足以快速修复:

string cleaned = new string(input.Where(c => !char.IsControl(c) && (char.IsLetterOrDigit(c) || char.IsPunctuation(c) || char.IsSeparator(c) || char.IsSymbol(c) || char.IsWhiteSpace(c))).ToArray());
于 2020-07-17T21:43:29.920 回答
-2
string output = new string(input.Where(c => !char.IsControl(c)).ToArray());

这肯定会解决问题。我在一个字符串中有一个不可打印的替代字符(ASCII 26),这导致我的应用程序中断,这行代码删除了这些字符

于 2016-09-29T15:56:56.923 回答