0

たとえば、処理された数式を(数字、文字、括弧を使用して)確認する方法を見つける必要があります。たとえば、この入力の場合:' 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;
    }

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

4

3 に答える 3

1

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

注意事項:

  • 置換を行うときは、現在の位置を更新して、新しい(変更された)文字列の繰り返し文字列の終わりを指すようにする必要があります
  • 0回の繰り返しが許可されているかどうかによっては、空の繰り返し、つまり空の文字列を処理する必要がある場合があります。
  • 文字列の最後に到達すると、スタックは空になります(すべての開き括弧が閉じ括弧と一致しました)
  • 文字列の途中でスタックが空になる可能性があります-閉じ括弧が見つかった場合、入力文字列の形式が正しくありませんでした
  • 開き/閉じ括弧をエスケープする方法がある可能性があるため、繰り返しパターンの一部としてカウントされません-これは要件によって異なります
于 2012-04-11T15:09:13.457 に答える
0

式の構文は再帰的であるため、再帰的なアプローチをお勧めします。

まず、式を単一のトークンに分割します。私Regexはそれを行い、空のエントリを削除するために使用します。

例:"5(2(a)sz)"に分割されます"5", "(", "2", "(", "a", ")", "sz", ")"

列挙子を使用すると、トークンを1つずつ取得できます。tokens.MoveNext()次のトークンを取得します。tokens.Current現在のトークンです。

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

ここでは、主な仕事は再帰的に行われます。

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;
}
于 2012-04-11T16:35:09.010 に答える
0

これが私の2番目の答えです。私の最初の答えは簡単なショットでした。ここでは、物事を1つずつ実行してパーサーを作成しようとしました。

式を変換するには、式を解析する必要があります。これは、その構文を分析する必要があることを意味します。その構文を分析しながら、出力を生成することもできます。

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

ここでは、EBNFを使用してそれを行います。EBNFは単純です。

{}繰り返しを囲みます(おそらくゼロ)。オプションパーツ
[を同封します。選択肢を分離します。 ]
|

EBNFの詳細については、ウィキペディアの拡張バッカスナウア記法(EBNF)を参照してください。(ここで使用されるEBNFバリアントは、連結演算子 "、"を削除します)。

EBNFでの構文

式={用語}。
項=[数値]係数。
ファクター=テキスト| "("式 ")" | 期間。

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

2字句解析

構文を分析する前に、式全体を単一の字句トークン(数値、演算子など)に分割する必要があります。enumトークンタイプを示すためにを使用します

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

_error次のフィールドは、トークン情報と、解析中にエラーが発生したかどうかを示すブール値を保持するために使用されます。

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();
    }
}
于 2012-04-11T22:03:05.057 に答える