C#:从字符串中删除常见的无效字符:改进此算法

p.c*_*ell 17 .net c# algorithm

考虑从字符串中删除无效字符的要求.只需删除字符并替换为空格或string.Empty.

char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example

foreach (char bad in BAD_CHARS)
{
    if (someString.Contains(bad))
      someString = someString.Replace(bad.ToString(), string.Empty);
}
Run Code Online (Sandbox Code Playgroud)

真的很喜欢这样做:

if (BAD_CHARS.Any(bc => someString.Contains(bc)))
    someString.Replace(bc,string.Empty); // bc is out of scope
Run Code Online (Sandbox Code Playgroud)

问题: 您对重构此算法或任何更简单,更易于阅读,高性能,可维护的算法有什么建议吗?

CAb*_*ott 36

我不知道它的可读性,但正则表达式可以满足您的需要:

someString = Regex.Replace(someString, @"[!@#$%_]", "");
Run Code Online (Sandbox Code Playgroud)

  • @Noldorin:我不同意.使用正则表达式只会发生一次新字符串的组合,并且很多次使用大量的Replace调用.组装一个新字符串意味着分配内存(=昂贵),Regex.Replace具有更好的缓存局部性(=更便宜) (2认同)

Run*_* FS 23

char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example
someString = string.Concat(someString.Split(BAD_CHARS,StringSplitOptions.RemoveEmptyEntries));
Run Code Online (Sandbox Code Playgroud)

应该做的伎俩(抱歉我的手机上有任何较小的语法错误)


Nol*_*rin 18

string类是不可变的(虽然引用类型),因此,它的所有的静态方法被设计为返回一个新的 string变量.调用someString.Replace而不将其分配给任何内容将不会对您的程序产生任何影响. - 好像你解决了这个问题.

您建议的算法的主要问题是它重复分配许多新string变量,可能会导致性能大幅下降.LINQ在这里并没有真正的帮助.(在我看来,我不会使代码明显缩短,当然也不会更具可读性.)

请尝试以下扩展方法.关键是使用StringBuilder,这意味着在执行期间只为结果分配了一个内存块.

private static readonly HashSet<char> badChars = 
    new HashSet<char> { '!', '@', '#', '$', '%', '_' };

public static string CleanString(this string str)
{
    var result = new StringBuilder(str.Length);
    for (int i = 0; i < str.Length; i++)
    {
        if (!badChars.Contains(str[i]))
            result.Append(str[i]);
    }
    return result.ToString();
}
Run Code Online (Sandbox Code Playgroud)

该算法还利用.NET 3.5'HashSet'类来提供O(1)检测错误char的查找时间.这使得整个算法O(n)而不是O(nm)你发布的算法(m是不良字符的数量); 如上所述,内存使用情况也好得多.

  • 如果使用哈希表/字典来存储错误字符,则查找将是O(1)而不是O(m).这也可以允许自定义替换角色(即,如果他想在将来用'at'替换''而不是''. (4认同)

Sam*_*ell 7

这一次比快HashSet<T>.此外,如果您必须经常执行此操作,请考虑我在此处提出的此问题的基础.

private static readonly bool[] BadCharValues;

static StaticConstructor()
{
    BadCharValues = new bool[char.MaxValue+1];
    char[] badChars = { '!', '@', '#', '$', '%', '_' };
    foreach (char c in badChars)
        BadCharValues[c] = true;
}

public static string CleanString(string str)
{
    var result = new StringBuilder(str.Length);
    for (int i = 0; i < str.Length; i++)
    {
        if (!BadCharValues[str[i]])
            result.Append(str[i]);
    }
    return result.ToString();
}
Run Code Online (Sandbox Code Playgroud)