2016-01-27 101 views
-1

我有一個字符串,我必須解析,從它正確設置類變量。該字符串結構嚴重,但我無法改變它。我試圖解析它,但沒有一個好的方法來做到這一點沒有問題。字符串本身是一組用於從cmd行觸發exe的屬性和參數。解析邏輯證明非常複雜

我已經制定了一個更容易閱讀,但知道它是1連續字符串。

以下是關於如何閱讀此行的規則。 對於每個'非-dll'命令,您都可以預期單個鍵和值對。對於dll行,您可以在初始dll =,'即'dll'元素包含0個或多個keyValue或單獨的空值分隔值之後擁有單個或多個鍵值對。例如 DLL = oneMoreDll,andItsParam =值anotherParam =值lastParam =值值

輸入字符串

時間=值1大小=值2 DLL = aDllName DLL = anotherDllName,someParam = ParamValue DLL = yetAnotherDll, someOhterParam = anotherParamValue aStandAloneValue DLL = oneMoreDll,andItsParam =值anotherParam =值lastParam =值

我希望能夠將此字符串解析爲以下格式,想到在一個字符串數組的每一行。

我試圖分裂的空格,然後'DLL',但我的正則表達式aint達到劃痕或不可能(我確定它不是)。幫幫我!

希望的輸出的元件,將被存儲在一個字符串數組

time=value1 
size=value2 
dll=aDllName 
dll=anotherDllName, someParam=ParamValue 
dll=yetAnotherDll, someOhterParam=anotherParamValue aStandAloneValue 
dll=oneMoreDll, andItsParam=value anotherParam=value lastParam=value 
+1

爲什麼不用空格拆分,然後用'='進一步拆分結果? – Rob

+0

按空格分割會導致dll字符串碎片化,其中包含空格,我想將每個dll細節放在一起 - 有些不包含params – Fearghal

+1

您的問題是什麼?顯示預期的輸入和輸出並**解釋**。 **爲什麼**還要''dll = anotherDllName,someParam = ParamValue'屬於一起,'和ItsParam = value anotherParam = value lastParam = value',但是'attribute1 = value1'和'attribute2 = value2'不是? – CodeCaster

回答

2

以下應該工作,至少對於示例情況。

  1. 分割字符串由 '通過
  2. 分割每個子串 '=''。如果沒有'=',我們只需要走左邊。

我們現在只剩下這看起來是這樣的結構:

現在,我們由之前的「DLL」需要的診斷項目

{ left = attribute1, right = value1 }, { left = attribute2, right = value2 }, { left = aStandAloneValue }等。我使用從this answer獲取的擴展方法來幫助解決這個問題。

本質上,它將組合,直到條件是不是會見。在我們的案例中,我們希望在我們點擊「dll」條目時停止分組。或者,如果我們還沒有創建「dll」條目,那麼我們總是會創建一個新的組。

其餘的只是格式化輸出(可能不需要你的情況)。

var inStr = "time=value1 size=value2 dll=aDllName dll=anotherDllName, someParam=ParamValue dll=yetAnotherDll, someOhterParam=anotherParamValue aStandAloneValue dll=oneMoreDll, andItsParam=value anotherParam=value lastParam=value"; 

bool isBeforeAnyDll = true; 

var result = inStr.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) 
    .Select(r => { 
     var split = r.Split('='); 
     if (split.Length == 1) 
      return new { left = split[0], right = (string)null }; 

     var left = split[0]; 
     var right = split[1]; 
     return new { left, right }; 
    }) 
    .GroupAdjacentBy((l, r) => { 
     return r.left == "dll" 
      ? isBeforeAnyDll = false 
      : !isBeforeAnyDll; 
    }) 
    .Select(g => string.Join(" ", 
     g.Select(gg => { 
      if (gg.right == null) 
       return gg.left; 
      return string.Format("{0}={1}", gg.left, gg.right); 
     }))); 


//https://stackoverflow.com/a/4682163/563532 
public static class LinqExtensions 
{ 
    public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
     this IEnumerable<T> source, Func<T, T, bool> predicate) 
    { 
     using (var e = source.GetEnumerator()) 
     { 
      if (e.MoveNext()) 
      { 
       var list = new List<T> { e.Current }; 
       var pred = e.Current; 
       while (e.MoveNext()) 
       { 
        if (predicate(pred, e.Current)) 
        { 
         list.Add(e.Current); 
        } 
        else 
        { 
         yield return list; 
         list = new List<T> { e.Current }; 
        } 
        pred = e.Current; 
       } 
       yield return list; 
      } 
     } 
    } 
} 

輸出:

time=value1 
size=value2 
dll=aDllName 
dll=anotherDllName, someParam=ParamValue 
dll=yetAnotherDll, someOhterParam=anotherParamValue aStandAloneValue 
dll=oneMoreDll, andItsParam=value anotherParam=value lastParam=value 

數據的.GroupAdjacentBy()後所有適當組合在一起,下面的代碼被簡單地格式化的輸出。

+1

你能解釋一下這個代碼實現的_logic_,以便幫助OP驗證它是否做到了他們想要的,所以後來遇到這種情況的訪問者可以理解它嗎? – CodeCaster

+1

哇,那brill ....幾乎那裏,只是經過測試,我的代碼在正確的線上吐出'dll'的東西aut不分隔時間和大小,它們出現在一條連續的線上。如果你願意,我可以從這裏拿它,只是想我會讓你知道的 – Fearghal

+0

@ Fearghal我已經更新它,因爲你已經測試過了,現在它會把時間和大小放在不同的線上:) – Rob

0

爲什麼不Enviroment.NewLine分裂然後通過,然後由第一=符號分割,採取左側部分作爲變量名,然後右邊部分作爲變量值?

0

可以使用Regex.Matches使用下面的正則表達式的方法:

using System; 
using System.Linq; 
using System.Text.RegularExpressions; 
public class Test 
{ 
    public static void Main() 
    { 
     var log = "time=value1 size=value2 dll=aDllName dll=anotherDllName, someParam=ParamValue dll=yetAnotherDll, someOhterParam=anotherParamValue aStandAloneValue dll=oneMoreDll, andItsParam=value anotherParam=value lastParam=value"; 
     var res = Regex.Matches(log, @"\bdll=(?:(?!\bdll=).)*|\w+=\w+") 
       .Cast<Match>() 
       .Select(p => p.Value) 
       .ToList(); 
     Console.WriteLine(string.Join("\n",res)); 
    } 
} 

IDEONE demoregex demo

正則表達式匹配2層的替代品:

  • \bdll= - 整字dll=接着用...
  • (?:(?!\bdll=).)* - 零個或多個字符不dll
  • | - 或....
  • \w+=\w+ - 一個或多個字的字符,隨後用=隨後與一個或多個單詞字符。
+0

對不起Wiktor,爲了簡化,我給了你一個確實無效的槓桿,我用更實際的值更新了Q值 - 而不是屬性值和2我的意思是我有一個隨機字符串,例如'時間'或'蛋'或'沙拉' – Fearghal

+0

我更新了代碼。 –