我正在使用此方法来清理字符串
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;
}
此方法工作正常..但此方法存在性能故障。每当我传递字符串时,每个字符都进入循环,如果我有一个大字符串,那么返回该对象将花费太多时间。
还有其他更好的做同样事情的方法吗?比如LINQ或JQUERY / Javascript
任何建议都将不胜感激。
答案 0 :(得分:36)
好的,请考虑以下测试:
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>
....
}
}
<强>输出强>
CleanString.UseReplace: 791
CleanString.UseStringBuilder: 2805
CleanString.UseStringBuilderWithHashSet: 521
CleanString.UseStringBuilderWithHashSet2: 331
CleanString.UseRegex: 1700
CleanString.UseWhere: 233
<强>结论强>
使用哪种方法可能无关紧要。
禁用(UseWhere
:233ms)和最慢(UseStringBuilder
:2805ms)方法之间的时间差为2572ms,连续调用50000(!)次。如果不经常运行该方法,您可能不需要关心它。
但如果你这样做,请使用UseWhere
方法(由L.B编写);但也要注意它略有不同。
答案 1 :(得分:5)
如果你追求纯粹的速度和效率,我建议做这样的事情:
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();
}
RegEx当然是一个优雅的解决方案,但它增加了额外的开销。通过指定字符串构建器的起始长度,它只需要分配一次内存(最后一次分配ToString
)。这将减少内存使用量并提高速度,尤其是在较长的字符串上。
然而,作为L.B.说,如果你使用它来正确编码绑定到HTML输出的文本,你应该使用HttpUtility.HtmlEncode
而不是自己做。
答案 2 :(得分:3)
使用正则表达式[?&^$#@!()+-,:;<>’\'-_*]
替换空字符串
答案 3 :(得分:2)
我不知道在性能方面,使用Regex
或LINQ是否会有所改善
可能有用的东西是使用StringBuilder
创建新字符串,而不是每次都使用string.Replace
:
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();
}
}
答案 4 :(得分:1)
答案 5 :(得分:1)
或许首先解释'为什么'然后再解释'什么'是有帮助的。您的性能降低的原因是因为c#copies-and -c替换每个替换的字符串。根据我在.NET中使用Regex的经验并不总是更好 - 尽管在大多数情况下(我认为包括这个)它可能会正常工作。
如果我真的需要性能,我通常不会让运气好,只需告诉编译器我想要的是什么:即:创建一个带有上限字符数的字符串并复制那里的所有字符需要。也可以用开关/ case或数组替换hashset,在这种情况下你最终可能会跳转表或数组查找 - 这甚至更快。
'务实'最好,但快速的解决方案是:
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);
BTW:当您想要处理高代理Unicode字符时,此解决方案不正确 - 但可以轻松调整以包含这些字符。
-Stefan。
答案 6 :(得分:1)
这个更快! 使用:
string dirty=@"tfgtf$@$%gttg%$% 664%$";
string clean = dirty.Clean();
public static string Clean(this String name)
{
var namearray = new Char[name.Length];
var newIndex = 0;
for (var index = 0; index < namearray.Length; index++)
{
var letter = (Int32)name[index];
if (!((letter > 96 && letter < 123) || (letter > 64 && letter < 91) || (letter > 47 && letter < 58)))
continue;
namearray[newIndex] = (Char)letter;
++newIndex;
}
return new String(namearray).TrimEnd();
}
答案 7 :(得分:0)
我无法在酸性测试上花费时间,但这条线实际上并没有按照需要清理斜线。
HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’\'-_*");
我必须单独添加斜杠并转义反斜杠
HashSet<char> removeChars = new HashSet<char>(" ?&^$#@!()+-,:;<>’'-_*");
removeChars.Add('/');
removeChars.Add('\\');
答案 8 :(得分:0)
我在当前项目中使用了它,并且效果很好。它使用一个句子,删除所有非字母数字字符,然后返回该句子,其中所有单词的首字母大写,其他所有字母均小写。也许我应该将其称为SentenceNormalizer。命名很困难:)
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;
}