に行われ
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();
}
}
私はそれがどのように動作しているのかを断言しませんでした。 – Noam650
理解しにくい部分はありますか? – Attila
私はそれをスタックなしでやったし、うまくいきません。同じ方法で。 – Noam650