あなたが「低レベル」に移動し、文字列は、使用する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()); }
タプルでは、それは複雑になり何を「緩和」するためにいくつかのヘルパー(いわば)可読性[それはもはや技術的にワンライナーではありませんが]
//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#0は同じ味でビット)
は、1にも
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は文字列を想定しています。文字列ビルダーのAny()メソッドはありません。 – mybirthname