你可以去到“低级别”,并使用的事实,一个字符串是一个IEnumerable<char>
使用它的GetEnumerator
string Format(string str, string separator)
{
var builder = new StringBuilder (str.Length);
using (var e = str.GetEnumerator())
{
while (e.MoveNext())
{
bool hasMoved = true;
if (!char.IsLetterOrDigit (e.Current))
{
while ((hasMoved = e.MoveNext()) && !char.IsLetterOrDigit (e.Current))
;
builder.Append (separator);
}
if (hasMoved)
builder.Append (e.Current);
}
}
return builder.ToString();
}
以防万一这里是一个正则表达式版本太多
private static readonly Regex rgx = new Regex(@"[^\w-[_]]+", RegexOptions.Compiled);
string Format (string str, string separator)
{
return rgx.Replace (str, separator);
}
关于对LINQ的一行OP的评论附录:
这是可能的,但几乎没有“容易理解”
使用匿名类型
string Format (string str, string separator)
{
return str.Aggregate (new { builder = new StringBuilder (str.Length), prevDiscarded = false }, (state, ch) => char.IsLetterOrDigit (ch) ? new { builder = (state.prevDiscarded ? state.builder.Append (separator) : state.builder).Append (ch), prevDiscarded = false } : new { state.builder, prevDiscarded = true }, state => (state.prevDiscarded ? state.builder.Append (separator) : state.builder).ToString());
}
同样的事情用一个元组,而不是
string Format (string str, string separator)
{
return str.Aggregate (Tuple.Create (new StringBuilder (str.Length), false), (state, ch) => char.IsLetterOrDigit (ch) ? Tuple.Create ((state.Item2 ? state.Item1.Append (separator) : state.Item1).Append (ch), false) : Tuple.Create (state.Item1, true), state => (state.Item2 ? state.Item1.Append (separator) : state.Item1).ToString());
}
和Tuple我们可以做一些助手来“缓和”(这么说)可读性[尽管它在技术上不是一个衬垫了]
//top of file
using State = System.Tuple<System.Text.StringBuilder, bool>;
string Format (string str, string separator)
{
var initialState = Tuple.Create (new StringBuilder (str.Length), false);
Func<State, StringBuilder> addSeparatorIfPrevDiscarded = state => state.Item2 ? state.Item1.Append (separator) : state.Item1;
Func<State, char, State> aggregator = (state, ch) => char.IsLetterOrDigit (ch) ? Tuple.Create (addSeparatorIfPrevDiscarded (state).Append (ch), false) : Tuple.Create (state.Item1, true);
Func<State, string> resultSelector = state => addSeparatorIfPrevDiscarded (state).ToString();
return str.Aggregate (initialState, aggregator, resultSelector);
}
是什么使得它复杂的是,(IMO)的LINQ *是不是真的适合当“项目输出“取决于同一集合中的前一个(或下一个)项目
* Linq并没有问题,但它很快就会产生大量的Func和匿名类型/元组语法(可能是C#7)。0将改变一个位)
在相同的味道,人们还可以接受的副作用,允许只具有布尔作为国家
string Format (string str, string separator)
{
var builder = new StringBuilder (str.Length);
Action<bool> addSeparatorIfPrevDiscarded = prevDiscarded => { if (prevDiscarded) builder.Append (separator); };
Func<bool, char, bool> aggregator = (prevDiscarded, ch) => {
if (char.IsLetterOrDigit (ch)) {
addSeparatorIfPrevDiscarded (prevDiscarded);
builder.Append (ch);
return false;
}
return true;
};
addSeparatorIfPrevDiscarded (str.Aggregate (false, aggregator));
return builder.ToString();
}
**?也更适合http://codereview.stackexchange.com/ – Sehnsucht
如果你保持跟踪,如果前一个字符是非字母数字的,你可以消除对列表和连接的需要,所以你知道何时将分隔符附加到'StringBuilder '。 'StringBuilder'没有我知道的'Any'方法,所以'sb.Count> 0'可能就是你想要的。 – juharr
此代码无法编译,string.Join expect字符串,没有方法任何()字符串生成器。 – mybirthname