2012-02-21 20 views
5

私の最終的な目標は以下の文字列をJSONに変えることですが、フィールド名とそれぞれの値を組み合わせることで一歩近づけることができます。Regexの一致/置換パターンに関する助けが必要

サンプルデータ:

Field1:abc,Field1:def,Field2:asd,Field2:fgh 

それを行うことができる場合には最終的に、この結果は素晴らしいだろう:Regex.Replaceを(使用

Field1:abc;def;Field2:asd;fgh; 

)、私はそれが、少なくともこのように見てする必要があります1回の呼び出しでRegex経由で。

私はこのパターンのさまざまなバリエーションを試してみたが、それは右のように見えることはできません
{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"} 

:ちょうど

(?:(\w+):)*?(?:([^:;]+);) 

つだけ、他の例を私は似た何かをやっている見つけることができるが、私はそれに私の指を置くことはできません十分な違い。

Regex to repeat a capture across a CDL?

EDIT: 

ここに私のソリューションです。他の人によって投稿されたものに信用を与えたいので、私は「解決策」として投稿するつもりはありません。結局のところ、私はポストされた各ソリューションから1枚を取り出し、これを思い付いた。投稿した皆様に感謝します。私は、コンパイルされ、最も速く実行され、最も正確な結果を得たソリューションに賞賛しました。

string hbi = "Field1:aaa;bbb;ccc;ddd;Field2:111;222;333;444;"; 

    Regex re = new Regex(@"(\w+):(?:([^:;]+);)+"); 
    MatchCollection matches = re.Matches(hbi); 

    SortedDictionary<string, string> dict = new SortedDictionary<string, string>(); 

    for (int x = 0; x < matches.Count; x++) 
    { 
     Match match = matches[x]; 
     string property = match.Groups[1].Value; 

     for (int i = 0; i < match.Groups[2].Captures.Count; i++) 
     { 
      string key = i.ToString() + x.ToString(); 
      dict.Add(key, string.Format("\"{0}\":\"{1}\"", property, match.Groups[2].Captures[i].Value)); 
     } 
    } 
    Console.WriteLine(string.Join(",", dict.Values)); 
+0

LINQのパフォーマンスが正規表現に近い場合、私はゲームです。 –

+0

大きな入力文字列を比較すると面白いです – sll

+0

私は同意します。ここに示された同じデータは、私が変換しようとしているものと比較して非常に小さいです。実際のオブジェクトは31個のフィールドを含み、100〜200個のオブジェクトを含むことができます。 –

答えて

1

私は、これを短く、より明確な方法で行うことができるはずであるという考えがありました。それはそれほど短くなくなってしまったので、それがもっと明確かどうか疑問に思うことができます。少なくともそれは問題を解決する別の方法です。

var str = "Field1:abc;def;Field2:asd;fgh"; 
var rows = new List<Dictionary<string, string>>(); 
int index = 0; 
string value; 
string fieldname = ""; 

foreach (var s in str.Split(';')) 
{ 
    if (s.Contains(":")) 
    { 
     index = 0; 
     var tmp = s.Split(':'); 
     fieldname = tmp[0]; 
     value = tmp[1]; 
    } 
    else 
    { 
     value = s; 
     index++; 
    } 

    if (rows.Count < (index + 1)) 
     rows.Insert(index, new Dictionary<string, string>()); 

    rows[index][fieldname] = value; 
} 

var arr = rows.Select(dict => 
        String.Join("," , dict.Select(kv => 
         String.Format("\"{0}\":\"{1}\"", kv.Key, kv.Value)))) 
        .Select(r => "{" + r + "}"); 
var json = String.Join(",", arr); 
Debug.WriteLine(json); 

出力:

{"Field1":"abc","Field2":"asd"},{"Field1":"def","Field2":"fgh"} 
+0

ありがとうございました。コンパイルされたソリューションは、(他のコンパイル可能なソリューションの中でも)最も速く、最も正確な結果を提供しました。 –

2

Now you have two problems

私は正規表現がこれを処理するための最良の方法だろうとは思いません。おそらく、セミコロンを分割して、 "Field1:"または "Field2:"で始まる値を探して結果をループし、その結果を辞書に集めてください。

トリート私はそれをコンパイルしたりテストしていないので、擬似コードとしてこの:

string[] data = input.Split(';'); 
dictionary<string, string> map = new dictionary<string, string>(); 

string currentKey = null; 
foreach (string value in data) 
{ 
    // This part should change depending on how the fields are defined. 
    // If it's a fixed set you could have an array of fields to search, 
    // or you might need to use a regular expression. 
    if (value.IndexOf("Field1:") == 0 || value.IndexOf("Field2:")) 
    { 
     string currentKey = value.Substring(0, value.IndexOf(":")); 
     value = value.Substring(currentKey.Length+1); 
    } 
    map[currentKey] = value; 
} 
// convert map to json 
+1

うん... 'ブルールフォースの方法です。ループ。 C#4.0、Linq、Dynamics、Genericsなどでは、この予測可能なフォーマットをループのないJSONにデシリアライズする方法が必要です。 –

+4

私はループを避ける方法があると確信していますが、なぜそれをより複雑にするのですか?あなたがループを見ていなくても、それはLinqなどと一緒にそこに残っています。 – mcrumley

+0

私の主張は、C#が1.0から長い道のりを歩んできたことです。 Regexのパターンがうまくいくと思います。だから、私はむしろその解決策に行き、オブジェクトにJSON文字列を逆シリアル化したいと思います。文字列をループする場合は、デシリアライズしないで自分でオブジェクトを構築できます。 –

1

私はパース文字列に最も単純で簡単な方法として、正規表現で行くだろうが、私は申し訳ありませんが、私は一発でこれを行うための賢明な十分な置換文字列を思いつくことができませんでした。

私はそれを楽しむためにそれをハッキングしました。そして、下の怪物は、あなたが必要とするものをぞっとするように達成します。 -/

 Regex r = new Regex(@"(?<FieldName>\w+:)*(?:(?<Value>(?:[^:;]+);)+)"); 

     var matches = r.Matches("Field1:abc;def;Field2:asd;fgh;moo;"); // Modified to test "uneven" data as well. 

     var tuples = new[] { new { FieldName = "", Value = "", Index = 0 } }.ToList(); tuples.Clear(); 

     foreach (Match match in matches) 
     { 
      var matchGroups = match.Groups; 
      var fieldName = matchGroups[1].Captures[0].Value; 
      int index = 0; 
      foreach (Capture cap in matchGroups[2].Captures) 
      { 
       var tuple = new { FieldName = fieldName, Value = cap.Value, Index = index }; 
       tuples.Add(tuple); 
       index++; 
      } 

     } 

     var maxIndex = tuples.Max(tup => tup.Index); 

     var jsonItemList = new List<string>(); 

     for (int a = 0; a < maxIndex+1; a++) 
     { 
      var jsonBuilder = new StringBuilder(); 
      jsonBuilder.Append("{"); 

      foreach (var tuple in tuples.Where(tup => tup.Index == a)) 
      { 
       jsonBuilder.Append(string.Format("\"{0}\":\"{1}\",", tuple.FieldName, tuple.Value)); 
      } 
      jsonBuilder.Remove(jsonBuilder.Length - 1, 1); // trim last comma. 
      jsonBuilder.Append("}"); 
      jsonItemList.Add(jsonBuilder.ToString()); 
     } 

     foreach (var item in jsonItemList) 
     { 
      // Write your items to your document stream. 
     } 
+0

LinqとLambdaを組み合わせたタプルの使い方。私はこれと一緒に行かなければならないかもしれませんが、私に似た質問があります。 のものは必要なく、Split()には何も持っていません。 http://stackoverflow.com/questions/2914587/regex-to-repeat-a-capture-across-a-cdl –

関連する問題