那么,你不需要第一个电话ToCharArray()
开始 - 字符串实现IEnumerable<char>
。不过,我同意在这种情况下,StringBuilder和循环可能更合适。
我不知道什么string.Concat(char [])做副手,顺便说一句 - 为什么你不只是使用字符串构造函数,它需要一个字符数组?换句话说,经过这些修改:
static string SanitizeXml(string xml)
{
return new string (xml.Where(c => IsLegalXmlChar(c)).ToArray());
}
我还是更喜欢StringBuilder的解决方案,但可能对于通常的情况得到改善(其中有几个非法字符)给予开始用适当的容量:
string SanitizeXml(string xml)
{
var buffer = new StringBuilder(xml.Length);
foreach(char c in xml)
{
if (IsLegalXmlChar(c))
{
buffer.Append(c);
}
}
return buffer.ToString();
}
一种替代我之前没有想到的可能是对的StringBuilder扩展方法:
// Can't just call it Append as otherwise StringBuilder.Append(object) would
// be used :(
public static StringBuilder AppendSequence(this StringBuilder builder,
IEnumerable<char> sequence)
{
foreach (char c in sequence)
{
builder.Append(c);
}
return builder;
}
然后,你可以使用它像这样:
xml = new StringBuilder(xml.Length)
.AppendSequence(xml.Where(IsLegalXmlChar)
.ToString();
(你可以有其他重载AppendSequence采取的IEnumerable等,如果你想。)
编辑:另一种方法是避免调用追加经常使用,而不是the overload which appends a substring。然后,您可以再建立StringBuilder的,像一个扩展方法(没有经过充分测试,我害怕 - 我还没有尝试过,甚至其编译):
public static StringBuilder AppendWhere(this StringBuilder builder,
string text,
Func<char, bool> predicate)
{
int start = 0;
bool lastResult = false;
for (int i=0; i < text.Length; i++)
{
if (predicate(text[i]))
{
if (!lastResult)
{
start = i;
lastResult = true;
}
}
else
{
if (lastResult)
{
builder.Append(text, start, i-start);
lastResult = false;
}
}
}
if (lastResult)
{
builder.Append(text, start, text.Length-start);
}
return builder;
}
使用的例子:
xml = new StringBuilder(xml.Length).AppendWhere(xml, IsLegalXmlChar)
.ToString();
另一种方法是将其更改为String上的扩展方法,懒惰地创建StringBuilder,并且如果以start = 0结束,只返回原始字符串。
为什么要删除非法字符,而不是让框架为你逃脱? – 2009-01-18 19:30:13
非法字符通常会通过文档和数据转换进入。例如,没有理由在XML文档中使用'\ b',事实上,您的主板会产生铃声,任何尝试使用这些数据的.NET XML API都会抛出异常。 – core 2009-01-24 21:41:55