2012-04-11 12 views
0

含まれる図形式Iは、この入力を、例えば、(単に数字、文字や括弧を使用して)処理した式 をconertする方法を見つける必要がある:「5(2(a)sz)」出力は次のようになります「aaszaaszaaszaaszaasz」 私はそのようにしてみました:変換または括弧

string AddChainDeleteBracks(int open, int close, string input) 
    { 
     string to="",from=""; 
     //get the local chain multipule the number in input[open-1] 

     //the number of the times the chain should be multiplied 
     for (int i = input[open - 1]; i > 0; i--) 
     { 
      //the content 
      for (int m = open + 1; m < close; m++) 
      { 
       to = to + input[m]; 
      } 
     } 

     //get the chain i want to replace with "to" 
     for (int j = open - 1; j <= close; j++) 
     { 
      from = from + input[j]; 
     } 
     String output = input.Replace(from, to); 
     return output; 
    } 

しかし、それは動作しません。これを解決するための良いアイデアはありますか?

答えて

1

開始括弧の位置は、その括弧に関連付けられた番号とともにスタックに格納できます(先入れ先出し、たとえばSystem.Collections.Generic.Stack)。最初の(つまり:次の)閉じ括弧に遭遇すると、スタックの一番上をポップします。これは、繰り返す必要がある(これまでの最も内側の)括弧の間の部分文字列の開始位置と終了位置を与えます。次に、元の文字列のこの部分(繰り返し番号を含む)を繰り返し文字列に置き換えます。文字列の最後に達するまで続けます。注意すべき

もの:

  • あなたは、交換を行うときに、それは今(修正)新しい文字列
  • でrepetiotion文字列の末尾を指すよう、あなたの現在の位置を更新する必要があります
  • 0の繰り返しが許可されているかどうかに応じて、空の繰り返しを処理する必要があります。つまり、空の文字列です。
  • 文字列の最後に到達すると、スタックは空になります(すべての開始括弧は、 )
  • スタックが文字列の途中で空白 - 閉じ括弧に遭遇した場合、入力文字列の形式が正しくありません
  • 括弧の開閉をエスケープする方法があるかもしれないので、反復パターンの一部としてカウントされません。これはあなたの必要条件に依存します
+0

私はそれがどのように動作しているのかを断言しませんでした。 – Noam650

+0

理解しにくい部分はありますか? – Attila

+0

私はそれをスタックなしでやったし、うまくいきません。同じ方法で。 – Noam650

0

あなたの式の構文は再帰的なものなので、再帰的アプローチを提案します。

最初に式を単一のトークンに分割します。私はRegexを使って空のエントリを削除します。

例:"5(2(a)sz)"は、あなたが、トークンを一つずつ取得することができます列挙子を使用し"5", "(", "2", "(", "a", ")", "sz", ")"

に分割されます。 tokens.MoveNext()は次のトークンを取得します。 tokens.Currentは現在のトークンです。ここでの主な仕事は、ここでは、再帰的な方法で

private string Parse(IEnumerator<string> tokens) 
{ 
    string s = ""; 
    while (tokens.Current != ")") { 
     int n; 
     if (tokens.Current == "(") { 
      if (tokens.MoveNext()) { 
       s += Parse(tokens); 
       if (tokens.Current == ")") { 
        tokens.MoveNext(); 
        return s; 
       } 
      } 
     } else if (Int32.TryParse(tokens.Current, out n)) { 
      if (tokens.MoveNext()) { 
       string subExpr = Parse(tokens); 
       var sb = new StringBuilder(); 
       for (int i = 0; i < n; i++) { 
        sb.Append(subExpr); 
       } 
       s += sb.ToString(); 
      } 
     } else { 
      s += tokens.Current; 
      if (!tokens.MoveNext()) 
       return s; 
     } 
    } 
    return s; 
} 
+0

ここで何をしましたか?わかりません! – Noam650

+0

あなたの式は入れ子になっています。つまり、カッコ内は他のカッコなどとなります。したがって、 'Parse'メソッドはそれ自身を呼び出し、内部式の変換式を外部式に返します。これは再帰と呼ばれます。デバッガを使って何が起こるかを見ることができます。コールスタックウィンドウを表示すると、コールがどのようにネストされているかもわかります。 –

0

に行われ

public string ConvertExpression(string expression) 
{ 
    IEnumerator<string> tokens = Regex.Split(expression, @"\b") 
        .Where(s => s != "") 
        .GetEnumerator(); 
    if (tokens.MoveNext()) { 
     return Parse(tokens); 
    } 
    return ""; 
} 

は私の第二の答えです。私の最初の答えはすばやかった。ここでは、1つずつ事を実行してパーサを作成しようとしました。

式を変換するには、構文解析する必要があります。つまり、構文を分析する必要があります。その構文を分析している間も、出力を生成することができます。

1最初に行うべきことは、すべての有効な式の構文を定義することです。

ここではEBNFを使用しています。 EBNFは簡単です。

{および}は、繰り返し(おそらくゼロ)を囲みます。
[および]は、オプションの部品を取り囲んでいます。
|は選択肢を分けます。

EBNFの詳細については、WikpediaのExtended Backus–Naur Form (EBNF)を参照してください。 (ここで使用されるEBNFバリアントは連結演算子 "、"を削除します)。

EBNF

における当社の構文
 
Expression = { Term }. 
Term = [ Number ] Factor. 
Factor = Text | "(" Expression ")" | Term. 

 
    5(2(a)sz) => aaszaaszaaszaaszaasz 
    5(2a sz) => aaszaaszaaszaaszaasz 
    2 3(a 2b)c => abbabbabbabbabbabbc 

2字句解析

我々は、単一の字句(番号、事業者に式全体を分割する必要がある構文を解析する前に、 、など)。 は、我々は次のフィールドは、トークン情報とエラーが解析中に発生したかどうかを示すブール_errorを保持するために使用されている

private enum TokenType 
{ 
    None, 
    LPar, 
    RPar, 
    Number, 
    Text 
} 

トークンタイプを示すためにenumを使用しています。

private IEnumerator<Match> _matches; 
TokenType _tokenType; 
string _text; 
int _number; 
bool _error; 

ConvertExpressionが変換を開始します。これは、式をRegex.Matchesと表される単一のトークンに分割します。 これらはGetTokenメソッドで使用され、Regex.Matchesがより有用な情報に変換されます。この情報は、上記のフィールドに格納されます。

public string ConvertExpression(string expression) 
{ 
    _matches = Regex.Matches(expression, @"\d+|\(|\)|[a-zA-Z]+") 
     .Cast<Match>() 
     .GetEnumerator(); 
    _error = false; 
    return GetToken() ? Expression() : ""; 
} 

private bool GetToken() 
{ 
    _number = 0; 
    _tokenType = TokenType.None; 
    _text = null; 
    if (_error || !_matches.MoveNext()) 
     return false; 

    _text = _matches.Current.Value; 
    switch (_text[0]) { 
     case '(': 
      _tokenType = TokenType.LPar; 
      break; 
     case ')': 
      _tokenType = TokenType.RPar; 
      break; 
     case '0': 
     case '1': 
     case '2': 
     case '3': 
     case '4': 
     case '5': 
     case '6': 
     case '7': 
     case '8': 
     case '9': 
      _tokenType = TokenType.Number; 
      _number = Int32.Parse(_text); 
      break; 
     default: 
      _tokenType = TokenType.Text; 
      break; 
    } 
    return true; 
} 

3構文意味解析

今、私たちは、私たちは、実際の解析と表現変換を実行するために必要なすべてを持っています。以下の各メソッドは、1つのEBNF構文生成を分析し、変換結果を文字列として返します。 EBNFからC#コードへの変換は簡単です。構文の繰り返しはC#ループ文に変換されます。 オプションはifステートメントに変換され、代替はswitchステートメントに変換されます。

// Expression = { Term }. 
private string Expression() 
{ 
    string s = ""; 
    do { 
     s += Term(); 
    } while (_tokenType != TokenType.RPar && _tokenType != TokenType.None); 
    return s; 
} 

// Term = [ Number ] Factor. 
private string Term() 
{ 
    int n; 
    if (_tokenType == TokenType.Number) { 
     n = _number; 
     if (!GetToken()) { 
      _error = true; 
      return " Error: Factor expected."; 
     } 

     string factor = Factor(); 
     if (_error) { 
      return factor; 
     } 
     var sb = new StringBuilder(n * factor.Length); 
     for (int i = 0; i < n; i++) { 
      sb.Append(factor); 
     } 
     return sb.ToString(); 
    } 
    return Factor(); 
} 

// Factor = Text | "(" Expression ")" | Term. 
private string Factor() 
{ 
    switch (_tokenType) { 
     case TokenType.None: 
      _error = true; 
      return " Error: Unexpected end of Expression."; 
     case TokenType.LPar: 
      if (GetToken()) { 
       string s = Expression(); 
       if (_tokenType == TokenType.RPar) { 
        GetToken(); 
        return s; 
       } else { 
        _error = true; 
        return s + " Error ')' expected."; 
       } 
      } else { 
       _error = true; 
       return " Error: Unexpected end of Expression."; 
      } 
     case TokenType.RPar: 
      _error = true; 
      GetToken(); 
      return " Error: Unexpected ')'."; 
     case TokenType.Text: 
      string t = _text; 
      GetToken(); 
      return t; 
     default: 
      return Term(); 
    } 
} 
+0

私の最初の答えはあまり説明しませんでした。私はここでより体系的に進めようとしており、これがNoam650 または他の誰かにとって有用であることを願っています。 –