2012-02-21 6 views
5

내 궁극적 인 목표는 다음 문자열을 JSON으로 변환하는 것이지만, 각 값과 fieldname을 결합하여 한 단계 더 가까워지는 뭔가를 해결할 것입니다.Regex match/replace 패턴에 대한 도움이 필요합니다.

샘플 데이터 : Regex.Replace()를 사용

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

, 나는 이상과 같이 할 필요 : 그것은 할 수 있으면

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

궁극적으로,이 결과가 좋지 않을까 Regex를 통해 한 번의 호출로

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

나는이 패턴의 다양한 변화를 시도했지만, 바로 그것을 얻을 수없는 것 :

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

하나의 다른 예는 내가 그 비슷한 일을 찾을 수 있지만, 단지 충분히 차이가있어서 손가락을 대지 않을 수 있습니다.

EDIT: 

Regex to repeat a capture across a CDL?

여기 내 솔루션입니다. 다른 사람들이 게시 한 크레딧을주고 싶기 때문에 "솔루션"으로 게시하지 않을 것입니다. 결국, 나는 게시 된 각 솔루션에서 조각을 가져 와서 이것을 만들었습니다. 게시 한 모든 사람에게 감사드립니다. 필자는 컴파일 된 솔루션을 가장 빨리 실행했으며 가장 정확한 결과를 얻었습니다.

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

경우에, 나는 게임입니다. –

+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); 

출력은 : LINQ의 성능이 정규식에 가까운

{"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 문자열을 내 객체에 deserialze하는 것이 좋습니다. 문자열을 반복 할 경우 비 직렬화없이 객체를 직접 만들 수 있습니다. –

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와 결합 된 Tuples를 잘 사용합니다. 나는 내가 원하는 것을하는 나의 것과 매우 유사한 질문이있는 것을 제외하고는 이것과 함께해야 할 수도있다. 항목이 필요하지 않으며 Split()을 수행 할 항목이 없습니다. http://stackoverflow.com/questions/2914587/regex-to-repeat-a-capture-across-a-cdl –

관련 문제