2012-02-01 13 views
5

文字列から情報を抽出しようとしています - 特定のFortranフォーマット文字列。 「」で区切られた書式フィールドと文字列を再帰的に解析する

F8.3, I5, 3(5X, 2(A20,F10.3)), 'XXX' 

と書式パターンが繰り返される何回連続示す括弧の前の数で、括弧の中のグループをフォーマット:文字列は次のようにフォーマットされます。したがって、上の文字列は次のように展開されます。

F8.3, I5, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 5X, A20,F10.3, A20,F10.3, 'XXX' 

私はC#でそのパターンに準拠した文字列を展開しようとしています。私は多くのスイッチとifステートメントでそれに取り掛かってきましたが、間違った方法をとっていないかどうか疑問に思っていますか?

いくつかの正規表現wizzardは、正規表現は1きちんと-一挙にこれを行うことができますことを考えれば、私は基本的には不思議でしたか?私は正規表現については何も知らないが、これが私の問題を解決できるかどうかは、それらを使う方法を学ぶ時間を置いておくことを検討している...一方、正規表現ではこれを並べ替えることができない場合、もう一つの方法を見ている。

答えて

0

私は以下の例のようにrecusive方法を使用することをお勧めし(テストしていません):

ResultData Parse(String value, ref Int32 index) 
{ 
    ResultData result = new ResultData(); 
    Index startIndex = index; // Used to get substrings 

    while (index < value.Length) 
    { 
     Char current = value[index]; 

     if (current == '(') 
     { 
      index++; 
      result.Add(Parse(value, ref index)); 
      startIndex = index; 
      continue; 
     } 
     if (current == ')') 
     { 
      // Push last result 
      index++; 
      return result; 
     } 

     // Process all other chars here 
    } 

    // We can't find the closing bracket 
    throw new Exception("String is not valid"); 
} 

あなたは多分、コードの一部を変更する必要がありますしかし、このメソッドは単純なコンパイラを書くときに使用しています。それは完了していませんが、ただの例です。

+0

私は終わりましたあなたが提案し、それが働いたようなものをやって。これは、助言に感謝しかし、再帰的ではありませんが、ダウン最低にネストの最高レベルから動作します。動作しているようです。まったく何もしませんでした残念ながら –

0

個人的に、私の代わりに再帰関数を使用してお勧めします。開始括弧を押すたびに、その部分を解析するために関数を再度呼び出します。私は再帰的なデータ構造に一致する正規表現を使用できるかどうかはわかりません。

編集:削除。間違った正規表現)

+0

これは '3(...(...)'、no? – duedl0r

+0

と一致します。私は正しくない正規表現を削除するために私の答えを編集しました。良いツールは、単に文字とカウント括弧で文字列の文字を調べて関数を記述し、再帰的な構造。たぶん、代わりに正規表現と一致する。閉じ括弧の数は括弧を開くの番号と一致したら、あなたはあなたの部分文字列を持っている。 – Jonathan

1

これは私が私の前の例を拡張してきたし、それはあなたの例とうまくテスト :)正規表現でなんとかしなければなりません。

// regex to match the inner most patterns of n(X) and capture the values of n and X. 
private static readonly Regex matcher = new Regex(@"(\d+)\(([^(]*?)\)", RegexOptions.None); 

// create new string by repeating X n times, separated with ',' 
private static string Join(Match m) 
{ 
    var n = Convert.ToInt32(m.Groups[1].Value); // get value of n 
    var x = m.Groups[2].Value; // get value of X 
    return String.Join(",", Enumerable.Repeat(x, n)); 
} 

// expand the string by recursively replacing the innermost values of n(X). 
private static string Expand(string text) 
{ 
    var s = matcher.Replace(text, Join); 
    return (matcher.IsMatch(s)) ? Expand(s) : s; 
} 

// parse a string for occurenses of n(X) pattern and expand then. 
// return the string as a tokenized array. 
public static string[] Parse(string text) 
{ 
    // Check that the number of parantheses is even. 
    if (text.Sum(c => (c == '(' || c == ')') ? 1 : 0) % 2 == 1) 
     throw new ArgumentException("The string contains an odd number of parantheses."); 

    return Expand(text).Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); 
} 
+0

おかげで、。 –

+0

私はちょうどあなたがこれを更新したことを見ました。私はちょうどそれを試してみましたが、それは動作しますが6F9.3,2I9,2(F9.4,3(I2、(F8.3)))、4(I2、F10.5)のようなもので失敗しました。私はそこにF8のためにわずかな間違いがあることを知っている。3には係数はありませんが、少なくともその状況にも対処するためには少なくともロバストなアルゴリズムが必要です...正規表現でこれを行うのはいいでしょうが、コードのメソッドとそれは正常に動作します。 –

0

今日これを書き直しました。これは1つの方法で行うことができることが判明:

private static string ExpandBrackets(string Format) 
    { 
     int maxLevel = CountNesting(Format); 

     for (int currentLevel = maxLevel; currentLevel > 0; currentLevel--) 
     { 
      int level = 0; 
      int start = 0; 
      int end = 0; 

      for (int i = 0; i < Format.Length; i++) 
      { 
       char thisChar = Format[i]; 
       switch (Format[i]) 
       { 
        case '(': 
         level++; 
         if (level == currentLevel) 
         { 
          string group = string.Empty; 
          int repeat = 0; 

          /// Isolate the number of repeats if any 
          /// If there are 0 repeats the set to 1 so group will be replaced by itself with the brackets removed 
          for (int j = i - 1; j >= 0; j--) 
          { 
           char c = Format[j]; 
           if (c == ',') 
           { 
            start = j + 1; 
            break; 
           } 
           if (char.IsDigit(c)) 
            repeat = int.Parse(c + (repeat != 0 ? repeat.ToString() : string.Empty)); 
           else 
            throw new Exception("Non-numeric character " + c + " found in front of the brackets"); 
          } 
          if (repeat == 0) 
           repeat = 1; 

          /// Isolate the format group 
          /// Parse until the first closing bracket. Level is decremented as this effectively takes us down one level 
          for (int j = i + 1; j < Format.Length; j++) 
          { 
           char c = Format[j]; 
           if (c == ')') 
           { 
            level--; 
            end = j; 
            break; 
           } 
           group += c; 
          } 

          /// Substitute the expanded group for the original group in the format string 
          /// If the group is empty then just remove it from the string 
          if (string.IsNullOrEmpty(group)) 
          { 
           Format = Format.Remove(start - 1, end - start + 2); 
           i = start; 
          } 
          else 
          { 
           string repeatedGroup = RepeatString(group, repeat); 
           Format = Format.Remove(start, end - start + 1).Insert(start, repeatedGroup); 
           i = start + repeatedGroup.Length - 1; 
          } 
         } 
         break; 

        case ')': 
         level--; 
         break; 
       } 
      } 
     } 

     return Format; 
    } 

CountNesting()はフォーマット文でネストブラケットの最高レベルを返しますが、メソッドのパラメータとして渡すことができます。 RepeatString()は、指定された回数だけ文字列を繰り返し、フォーマット文字列の括弧で囲まれたグループに置き換えます。

関連する問題