我想从字符串中删除所有特殊字符。允许输入A-Z(大写或小写)、数字(0-9)、下划线(_)或点符号(.)。

我有以下,它是有效的,但我怀疑(我知道!)它不是很有效:

    public static string RemoveSpecialCharacters(string str)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.Length; i++)
        {
            if ((str[i] >= '0' && str[i] <= '9')
                || (str[i] >= 'A' && str[i] <= 'z'
                    || (str[i] == '.' || str[i] == '_')))
                {
                    sb.Append(str[i]);
                }
        }

        return sb.ToString();
    }

最有效的方法是什么?正则表达式是什么样子的,它与普通字符串操作相比如何?

要清洗的字符串相当短,长度通常在10到30个字符之间。


当前回答

我想知道基于regx的替代品(可能是编译的)是否更快。必须测试,有人发现这是~5倍慢。

除此之外,您应该使用预期的长度初始化StringBuilder,这样在中间字符串增长时就不必复制它。

一个好的数字是原始字符串的长度,或者稍低一些(取决于函数输入的性质)。

最后,您可以使用一个查找表(范围0..127)来确定一个字符是否被接受。

其他回答

我觉得你的算法很有效。它是O(n),并且只查看每个字符一次。除非你在检查它们之前神奇地知道它们的值,否则你不会比这更好。

但是,我将把StringBuilder的容量初始化为字符串的初始大小。我猜您认为的性能问题来自内存重新分配。

旁注:检查A-z并不安全。你要包括[,\,],^,_和'…

旁注2:为了获得额外的效率,将比较按顺序排列,以减少比较的数量。(在最坏的情况下,你说的是8个比较,所以不要想太多。)这随你的预期输入而变化,但一个例子可以是:

if (str[i] >= '0' && str[i] <= 'z' && 
    (str[i] >= 'a' || str[i] <= '9' ||  (str[i] >= 'A' && str[i] <= 'Z') || 
    str[i] == '_') || str[i] == '.')

旁注3:如果出于某种原因,你真的需要它更快,那么switch语句可能更快。编译器应该为你创建一个跳转表,结果只有一个比较:

switch (str[i])
{
    case '0':
    case '1':
    .
    .
    .
    case '.':
        sb.Append(str[i]);
        break;
}

我将使用字符串替换为正则表达式搜索“特殊字符”,替换所有字符找到一个空字符串。

我觉得不错。我要做的唯一改进是用字符串的长度初始化StringBuilder。

StringBuilder sb = new StringBuilder(str.Length);

我建议创建一个简单的查找表,您可以在静态构造函数中初始化它,以将任何字符组合设置为有效。这让您可以进行快速、单一的检查。

edit

另外,为了提高速度,您需要将StringBuilder的容量初始化为输入字符串的长度。这将避免重新分配。这两种方法结合起来会给你速度和灵活性。

另一个编辑

我认为编译器可能会优化它,但作为风格和效率的问题,我建议foreach而不是for。

正则表达式如下所示:

public string RemoveSpecialChars(string input)
{
    return Regex.Replace(input, @"[^0-9a-zA-Z\._]", string.Empty);
}

但如果性能非常重要,我建议你在选择“正则表达式路径”之前做一些基准测试……