C# 清理绳子?有没有更好的办法?

C# 清理绳子?有没有更好的办法?,c#,asp.net,string,linq,C#,Asp.net,String,Linq,我正在使用此方法清理字符串 public static string CleanString(string dirtyString) { string removeChars = " ?&^$#@!()+-,:;<>’\'-_*"; string result = dirtyString; foreach (char c in removeChars) { result = result.Replace(c.ToString(

我正在使用此方法清理字符串

public static string CleanString(string dirtyString)
{
    string removeChars = " ?&^$#@!()+-,:;<>’\'-_*";
    string result = dirtyString;

    foreach (char c in removeChars)
    {
        result = result.Replace(c.ToString(), string.Empty);
    }

    return result;
}
publicstaticstringcleanstring(stringdirtystring)
{
字符串removeChars=“?&^$#@!()+-,:;'\'-\*”;
字符串结果=dirtyString;
foreach(removeChars中的字符c)
{
result=result.Replace(c.ToString(),string.Empty);
}
返回结果;
}
这个方法很好用。。但这种方法存在性能问题。每次我传递字符串时,每个字符都进入循环,如果我有一个大字符串,那么返回对象将花费太多时间

还有其他更好的方法做同样的事情吗?。就像在LINQ或JQUERY/Javascript中一样


如果您有任何建议,我们将不胜感激。

使用regex
[?&^$\35;@!()+-,:;'\'-\ u*]
替换为空字符串。

尝试一下:

如果您追求的是纯粹的速度和效率,我建议您这样做:

public static string CleanString(string dirtyString)
{
    HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
    StringBuilder result = new StringBuilder(dirtyString.Length);
    foreach (char c in dirtyString)
        if (!removeChars.Contains(c)) // prevent dirty chars
            result.Append(c);
    return result.ToString();
}
publicstaticstringcleanstring(stringdirtystring)
{
HashSet removeChars=新的HashSet(“?&^$#@!()+-,:;”\'-\*”;
StringBuilder结果=新的StringBuilder(dirtyString.Length);
foreach(dirtyString中的字符c)
如果(!removeChars.Contains(c))//防止脏字符
结果:追加(c);
返回result.ToString();
}
正则表达式当然是一个优雅的解决方案,但它增加了额外的开销。通过指定字符串生成器的起始长度,它只需要分配一次内存(最后为
ToString
分配第二次内存)。这将减少内存使用并提高速度,尤其是在较长的字符串上


但是,正如L.B.所说的,如果你使用这个来正确地编码HTML输出的文本,你应该使用<代码> HTTPosial.HtmlEncode < /C>而不是自己做。

<好,考虑下面的测试:

public class CleanString
{
    //by MSDN http://msdn.microsoft.com/en-us/library/844skk0h(v=vs.71).aspx
    public static string UseRegex(string strIn)
    {
        // Replace invalid characters with empty strings.
        return Regex.Replace(strIn, @"[^\w\.@-]", "");
    }

    // by Paolo Tedesco
    public static String UseStringBuilder(string strIn)
    {
        const string removeChars = " ?&^$#@!()+-,:;<>’\'-_*";
        // specify capacity of StringBuilder to avoid resizing
        StringBuilder sb = new StringBuilder(strIn.Length);
        foreach (char x in strIn.Where(c => !removeChars.Contains(c)))
        {
            sb.Append(x);
        }
        return sb.ToString();
    }

    // by Paolo Tedesco, but using a HashSet
    public static String UseStringBuilderWithHashSet(string strIn)
    {
        var hashSet = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
        // specify capacity of StringBuilder to avoid resizing
        StringBuilder sb = new StringBuilder(strIn.Length);
        foreach (char x in strIn.Where(c => !hashSet.Contains(c)))
        {
            sb.Append(x);
        }
        return sb.ToString();
    }

    // by SteveDog
    public static string UseStringBuilderWithHashSet2(string dirtyString)
    {
        HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
        StringBuilder result = new StringBuilder(dirtyString.Length);
        foreach (char c in dirtyString)
            if (removeChars.Contains(c))
                result.Append(c);
        return result.ToString();
    }

    // original by patel.milanb
    public static string UseReplace(string dirtyString)
    {
        string removeChars = " ?&^$#@!()+-,:;<>’\'-_*";
        string result = dirtyString;

        foreach (char c in removeChars)
        {
            result = result.Replace(c.ToString(), string.Empty);
        }

        return result;
    }

    // by L.B
    public static string UseWhere(string dirtyString)
    {
        return new String(dirtyString.Where(Char.IsLetterOrDigit).ToArray());
    }
}

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        var dirtyString = "sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf////fj()=/§(§&/(\"&sdfdf.dsf8908()=(=(sadfJJLef@ssyd€sdöf";
        var sw = new Stopwatch();

        var iterations = 50000;

        sw.Start();
        for (var i = 0; i < iterations; i++)
            CleanString.<SomeMethod>(dirtyString);
        sw.Stop();
        Debug.WriteLine("CleanString.<SomeMethod>: " + sw.ElapsedMilliseconds.ToString());
        sw.Reset();

        ....
        <repeat>
        ....       
    }
}

结论

使用哪种方法可能无关紧要

连续调用50000次(!)时,快速(
usehere
:233ms)和最慢(
UseStringBuilder
:2805ms)方法之间的时间差为2572ms。如果不经常运行该方法,您可能不需要关心它


但如果你这样做,请使用
usehere
方法(由L.B.编写);但也要注意,它略有不同。

我不知道从性能角度来看,使用
Regex
或LINQ是否会有所改进。
可能有用的方法是使用
StringBuilder
创建新字符串,而不是使用
string。每次替换

using System.Linq;
using System.Text;

static class Program {
    static void Main(string[] args) {
        const string removeChars = " ?&^$#@!()+-,:;<>’\'-_*";
        string result = "x&y(z)";
        // specify capacity of StringBuilder to avoid resizing
        StringBuilder sb = new StringBuilder(result.Length);
        foreach (char x in result.Where(c => !removeChars.Contains(c))) {
            sb.Append(x);
        }
        result = sb.ToString();
    }
}
使用System.Linq;
使用系统文本;
静态类程序{
静态void Main(字符串[]参数){
常量字符串removeChars=“?&^$#@!()+-,:;'\'-\*”;
字符串结果=“x&y(z)”;
//指定StringBuilder的容量以避免调整大小
StringBuilder sb=新StringBuilder(结果长度);
foreach(result.Where(c=>!removeChars.Contains(c))中的字符x){
某人附加(x);
}
结果=sb.ToString();
}
}

首先解释“为什么”,然后解释“什么”,也许会有所帮助。性能变慢的原因是c#复制并替换每次替换的字符串。从我的经验来看,在.NET中使用正则表达式并不总是更好——尽管在大多数情况下(我认为包括这一个),它可能会工作得很好

如果我真的需要性能,我通常不会让它靠运气,而是直接告诉编译器我想要什么:即:创建一个字符数上限的字符串,并复制所有需要的字符。还可以用开关/大小写或数组替换哈希集,在这种情况下,您可能会得到跳转表或数组查找,这会更快

“务实”的最佳快速解决方案是:

char[] data = new char[dirtyString.Length];
int ptr = 0;
HashSet<char> hs = new HashSet<char>() { /* all your excluded chars go here */ };
foreach (char c in dirtyString)
    if (!hs.Contains(c))
        data[ptr++] = c;
return new string(data, 0, ptr);
char[]data=新字符[dirtyString.Length];
int-ptr=0;
HashSet hs=new HashSet(){/*所有被排除的字符都在这里*/};
foreach(dirtyString中的字符c)
如果(!hs.包含(c))
数据[ptr++]=c;
返回新字符串(数据,0,ptr);
顺便说一句:当您想要处理高代理Unicode字符时,此解决方案是不正确的,但是可以很容易地调整以包含这些字符


-Stefan.

这一个更快
使用:

string dirty=@“tfgtf$@$%gttg%$%664%$”;
字符串clean=dirty.clean();
公共静态字符串清除(此字符串名称)
{
var namearray=新字符[name.Length];
var-newIndex=0;
对于(var index=0;index96和字母<123)| |(字母>64和字母<91)|(字母>47和字母<58)))
继续;
namearray[newIndex]=(Char)字母;
++新指数;
}
返回新字符串(namearray).TrimEnd();
}

我无法花时间进行酸性测试,但这一行实际上没有按要求清理斜线

HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
HashSet removeChars=新的HashSet(“?&^$#@!()+-,:;'\'-\*”;
我必须单独添加斜杠并避开反斜杠

HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’'-_*");
removeChars.Add('/');
removeChars.Add('\\');
HashSet removeChars=新的HashSet(“?&^$#@!()+-,:;”-”;
removeChars.Add(“/”);
removeChars.Add('\\');

我在当前的项目中使用了它,效果很好。它接受一个句子,删除所有非字母数字字符,然后返回一个句子,所有单词都是大写字母,其他所有单词都是小写字母。也许我应该称之为句子规范化者。命名很难:)


你清理字符串的目的是什么?我基本上是处理大量的Qurystring值…将所有字符放在正则表达式的字符类中,然后一次替换所有字符。定义“更好”。任何解决方案都会在字符上有一个循环。代码中的缺点是过度创建字符串对象,而不是eve上的循环
HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’'-_*");
removeChars.Add('/');
removeChars.Add('\\');
    internal static string StringSanitizer(string whateverString)
{
    whateverString = whateverString.Trim().ToLower();
    Regex cleaner = new Regex("(?:[^a-zA-Z0-9 ])", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
    var listOfWords = (cleaner.Replace(whateverString, string.Empty).Split(' ', StringSplitOptions.RemoveEmptyEntries)).ToList();
    string cleanString = string.Empty;
    foreach (string word in listOfWords)
    {
        cleanString += $"{word.First().ToString().ToUpper() + word.Substring(1)} ";
    }
    return cleanString;
}