考虑从字符串中删除无效字符的要求。只需删除字符并替换为空格或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);
}
我有非常喜欢来执行此操作:
if (BAD_CHARS.Any(bc => someString.Contains(bc)))
someString.Replace(bc,string.Empty); // bc is out of scope
问题: 您是否有任何关于重构此算法的建议,或任何更简单,更易于阅读,高性能,可维护的算法?
答案 0 :(得分:34)
我不知道它的可读性,但正则表达式可以满足您的需要:
someString = Regex.Replace(someString, @"[!@#$%_]", "");
答案 1 :(得分:22)
char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example
someString = string.Concat(someString.Split(BAD_CHARS,StringSplitOptions.RemoveEmptyEntries));
应该做的伎俩(抱歉我手机上的语法错误很少)
答案 2 :(得分:18)
- 似乎您解决了这个问题。 string
类是不可变的(虽然是引用类型),因此它的所有静态方法都被设计为返回 new 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();
}
该算法还利用.NET 3.5'HashSet'类为O(1)
查找检测错误char的时间。这使得整个算法O(n)
而不是您发布的算法的O(nm)
(m
是坏字符的数量);如上所述,内存使用情况也好得多。
答案 3 :(得分:7)
这个 比HashSet<T>
快。此外,如果您必须经常执行此操作,请考虑this question I asked here的基础。
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();
}
答案 4 :(得分:4)
如果您仍想以LINQy方式执行此操作:
public static string CleanUp(this string orig)
{
var badchars = new HashSet<char>() { '!', '@', '#', '$', '%', '_' };
return new string(orig.Where(c => !badchars.Contains(c)).ToArray());
}
答案 5 :(得分:4)
额外提示:如果您不想记住文件无效的char
数组,可以使用Path.GetInvalidFileNameChars()
。如果您想要路径,那就是Path.GetInvalidPathChars
private static string RemoveInvalidChars(string str)
{
return string.Concat(str.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
}
答案 6 :(得分:3)
为什么你真的喜欢这样做?代码绝对不简单,你只是强迫查询扩展方法进入你的代码。
另外,Contains
检查在概念上和从性能角度来看似乎都是多余的。 Contains
无论如何都必须遍历整个字符串,你也可以为每个字符调用Replace(bad.ToString(), string.Empty)
并忘记它是否真正存在。
当然,正则表达式总是一个选项,并且在这种情况下可能更具性能(如果不是更不清楚)。
答案 7 :(得分:3)
需要考虑的事项 - 如果这是用于密码(比方说),你想要扫描并保留好字符,并假设其他一切都不好。它更容易正确过滤或好事,然后尝试猜测所有坏事。
每个角色 如果性格好 - &gt;保留它(复制到缓冲区,无论如何。)
杰夫
答案 8 :(得分:2)
这很干净。将其限制为有效字符,而不是删除无效字符。你应该把它分成常数:
string clean = new string(@"Sour!ce Str&*(@ing".Where(c =>
@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.".Contains(c)).ToArray()