[英]C#: Removing common invalid characters from a string: improve this algorithm
考慮從字符串中刪除無效字符的要求。 只需要刪除字符並替換為blank或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
問題:您對重構此算法或任何更簡單,更易於閱讀,高性能,可維護的算法有什么建議嗎?
我不知道它的可讀性,但正則表達式可以滿足您的需要:
someString = Regex.Replace(someString, @"[!@#$%_]", "");
char[] BAD_CHARS = new char[] { '!', '@', '#', '$', '%', '_' }; //simple example
someString = string.Concat(someString.Split(BAD_CHARS,StringSplitOptions.RemoveEmptyEntries));
應該做的伎倆(抱歉我的手機上有任何較小的語法錯誤)
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();
}
該算法還利用.NET 3.5'HashSet'類為O(1)
查找檢測錯誤char的時間。 這使得整體算法O(n)
而不是您發布的算法的O(nm)
( m
是壞字符的數量); 如上所述,內存使用情況也好得多。
這個比更快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();
}
如果您仍想以LINQy方式執行此操作:
public static string CleanUp(this string orig)
{
var badchars = new HashSet<char>() { '!', '@', '#', '$', '%', '_' };
return new string(orig.Where(c => !badchars.Contains(c)).ToArray());
}
額外提示:如果您不想記住對文件無效的char
數組,可以使用Path.GetInvalidFileNameChars()
。 如果你想要Paths,那就是Path.GetInvalidPathChars
private static string RemoveInvalidChars(string str)
{
return string.Concat(str.Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
}
你為什么真的喜歡這樣做? 代碼絕對不簡單,你只是強迫查詢擴展方法進入你的代碼。
另外, Contains
檢查在概念上和從性能角度看都是多余的。 無論如何, Contains
必須遍歷整個字符串,你也可以為每個字符調用Replace(bad.ToString(), string.Empty)
並忘記它是否實際存在。
當然,正則表達式總是一種選擇,並且在這種情況下可能更具性能(如果不是更不清楚)。
需要考慮的事項 - 如果這是用於密碼(比如說),你想要掃描並保留好的角色 ,並假設其他一切都不好。 它更容易正確過濾或好事,然后嘗試猜測所有壞事。
對於每個字符如果字符是好的 - >保留它(復制到輸出緩沖區,無論如何。)
傑夫
這很干凈。 將其限制為有效字符,而不是刪除無效字符。 您可能應該將其拆分為常量:
string clean = new string(@"Sour!ce Str&*(@ing".Where(c =>
@"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ,.".Contains(c)).ToArray()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.