4

C#には次の文字列があります。

"aaa,bbbb.ccc|dddd:eee"

次に、それをで分割しnew char[] {',','.','|',':'}ます。この文字列を以前と同じ順序で同じ文字で再結合するにはどうすればよいですか?したがって、リストは以前とまったく同じになります。

string s = "aaa,bbbb.ccc|dddd:eee";
string[] s2 = s.Split(new char[] {',','.','|',':'});
// now s2 = {"aaa", "bbbb", "ccc", "dddd", "eee"}
// lets assume I done some operation, and
// now s2 = {"xxx", "yyy", "zzz", "1111", "222"}

s = s2.MagicJoin(~~~~~~);  // I need this

// now s = "xxx,yyy.zzz|1111:222";

編集

上記のサンプルではchar[]、​​サンプルのみであり、同じ順序ではなく、現実の世界ではすべてが同時に表示されるわけではありません。

編集

ちょっと考えてみてください。Regex.splitを使用してから、最初にgetで分割し、次にsplitでchar[]別のgetstring[]を使用して、後でそれらを元に戻します。たぶんうまくいくかもしれませんが、私はそれをコーディングする方法がわかりません。not the char[]string[]

4

4 に答える 4

3

ここにありMagicSplitます:

public IEnumerable<Tuple<string,char>> MagicSplit(string input, char[] split)
{    
    var buffer = new StringBuilder();
    foreach (var c in input)
    {
        if (split.Contains(c)) 
        {
            var result = buffer.ToString();
            buffer.Clear();
            yield return Tuple.Create(result,c);
        }
        else
        {
            buffer.Append(c);
        }
    }
    yield return Tuple.Create(buffer.ToString(),' ');
}

そして2つのタイプMagicJoin

public string MagicJoin(IEnumerable<Tuple<string,char>> split)
{
    return split.Aggregate(new StringBuilder(), (sb, tup) => sb.Append(tup.Item1).Append(tup.Item2)).ToString();
}

public string MagicJoin(IEnumerable<string> strings, IEnumerable<char> chars)
{
    return strings.Zip(chars, (s,c) => s + c.ToString()).Aggregate(new StringBuilder(), (sb, s) => sb.Append(s)).ToString();
}

使用法:

var s = "aaa,bbbb.ccc|dddd:eee";

// simple
var split = MagicSplit(s, new char[] {',','.','|',':'}).ToArray();
var joined = MagicJoin(split);    

// if you want to change the strings
var strings = split.Select(tup => tup.Item1).ToArray();
var chars = split.Select(tup => tup.Item2).ToArray();
strings[0] = "test";
var joined = MagicJoin(strings,chars);
于 2012-05-09T23:35:52.750 に答える
3

正規表現クラスを使用すると、これを行う方が簡単な場合があります。

input = Regex.Replace(input, @"[^,.|:]+", DoSomething);

DoSomethingは、問題のアイテムを変換するメソッドまたはラムダです。例:

string DoSomething(Match m)
{
    return m.Value.ToUpper();
}

この例では、「aaa、bbbb.ccc | dddd:eee」の出力文字列は「AAA、BBBB.CCC | DDDD:EEE」になります。

ラムダを使用すると、次のように非常に簡単に状態を維持できます。

int i = 0;
Console.WriteLine(Regex.Replace("aaa,bbbb.ccc|dddd:eee", @"[^,.|:]+",
    _ => (++i).ToString()));

出力:

1,2.3|4:5

アイテムに対してどのような変換を行っているかによって異なります。

于 2012-05-09T23:36:54.497 に答える
3

これで、区切り文字の任意の組み合わせが任意の順序で機能し、文字列内に区切り文字が実際に見つからない状況も可能になります。これを思い付くのに少し時間がかかりました、そしてそれを投稿したので、それは他のどの答えよりも複雑に見えます!

ああ、とにかくここに置いておきます。

public static string SplitAndReJoin(string str, char[] delimiters, 
  Func<string[], string[]> mutator)
{
  //first thing to know is which of the delimiters are 
  //actually in the string, and in what order
  //Using ToArray() here to get the total count of found delimiters
  var delimitersInOrder = (from ci in
                            (from c in delimiters
                             from i in FindIndexesOfAll(str, c)
                             select new { c, i })
                          orderby ci.i
                          select ci.c).ToArray();
  if (delimitersInOrder.Length == 0)
    return str;

  //now split and mutate the string
  string[] strings = str.Split(delimiters);
  strings = mutator(strings);
  //now build a format string
  //note - this operation is much more complicated if you wish to use 
  //StringSplitOptions.RemoveEmptyEntries
  string formatStr = string.Join("",
    delimitersInOrder.Select((c, i) => string.Format("{{{0}}}", i)
      + c));
  //deals with the 'perfect' split - i.e. there's always two values
  //either side of a delimiter
  if (strings.Length > delimitersInOrder.Length)
    formatStr += string.Format("{{{0}}}", strings.Length - 1);

  return string.Format(formatStr, strings);
}

public static IEnumerable<int> FindIndexesOfAll(string str, char c)
{
  int startIndex = 0;
  int lastIndex = -1;

  while(true)
  {
    lastIndex = str.IndexOf(c, startIndex);
    if (lastIndex != -1)
    {
      yield return lastIndex;
      startIndex = lastIndex + 1;
    }
    else
      yield break;
  }
}

そして、これを検証するために使用できるテストは次のとおりです。

[TestMethod]
public void TestSplitAndReJoin()
{
  //note - mutator does nothing
  Assert.AreEqual("a,b", SplitAndReJoin("a,b", ",".ToCharArray(), s => s));
  //insert a 'z' in front of every sub string.
  Assert.AreEqual("zaaa,zbbbb.zccc|zdddd:zeee", SplitAndReJoin("aaa,bbbb.ccc|dddd:eee",
    ",.|:".ToCharArray(), s => s.Select(ss => "z" + ss).ToArray()));
  //re-ordering of delimiters + mutate
  Assert.AreEqual("zaaa,zbbbb.zccc|zdddd:zeee", SplitAndReJoin("aaa,bbbb.ccc|dddd:eee",
    ":|.,".ToCharArray(), s => s.Select(ss => "z" + ss).ToArray()));
  //now how about leading or trailing results?
  Assert.AreEqual("a,", SplitAndReJoin("a,", ",".ToCharArray(), s => s));
  Assert.AreEqual(",b", SplitAndReJoin(",b", ",".ToCharArray(), s => s));
}

配列の要素を使って何かを実行し、個々の文字列を操作してから再度結合する必要があると想定していることに注意してください。そうしないと、おそらく元の文字列を保持することになります。

このメソッドは、動的フォーマット文字列を作成します。ここでは効率に関する保証はありません:)

于 2012-05-09T23:09:05.663 に答える
1

これはどう?


var x = "aaa,bbbb.ccc|dddd:eee";

var matches = Regex.Matches(x, "(?<Value>[^\\.,|\\:]+)(?<Separator>[\\.,|\\:]?)");

var result = new StringBuilder();

foreach (Match match in matches)
{
    result.AppendFormat("{0}{1}", match.Groups["Value"], match.Groups["Separator"]);
}

Console.WriteLine(result.ToString());
Console.ReadLine();

または、LINQが好きな場合(私はそうします):


var x = "aaa,bbbb.ccc|dddd:eee";
var matches = Regex.Matches(x, "(?<Value>[^\\.,|\\:]+)(?<Separator>[\\.,|\\:]?)");
var reassembly = matches.Cast<Match>().Aggregate(new StringBuilder(), (a, v) => a.AppendFormat("{0}{1}", v.Groups["Value"], v.Groups["Separator"])).ToString();
Console.WriteLine(reassembly);
Console.ReadLine();

言うまでもなく、この演習のポイントは、再組み立てする前にパーツを使って何かを行うことができると思います。

于 2012-05-09T23:39:31.040 に答える