C# 转换或计算包含括号的公式

C# 转换或计算包含括号的公式,c#,parentheses,C#,Parentheses,我需要找到一种方法来转换经过处理的公式(仅使用数字、字母和括号) 例如,对于此输入:“5(2(a)sz)”输出应为:“aaszaaszaasz” 我试着这样做: string AddChainDeleteBracks(int open, int close, string input) { string to="",from=""; //get the local chain multipule the number in input[open-1]

我需要找到一种方法来转换经过处理的公式(仅使用数字、字母和括号) 例如,对于此输入:“
5(2(a)sz)
”输出应为:“
aaszaaszaasz
” 我试着这样做:

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;
    }
string AddChainDeleteBracks(int-open、int-close、string-input)
{
字符串to=“”,from=“”;
//获取输入[open-1]中的数字的本地链
//链应该相乘的次数
对于(int i=输入[open-1];i>0;i--)
{
//内容
对于(int m=open+1;m对于(int j=open-1;j您可以将左括号位置以及与该括号关联的数字存储在堆栈中(例如,后进先出);然后当遇到第一个时(即:下一个)关闭圆括号,弹出堆栈顶部:这将为您提供需要重复的圆括号(目前为止最内部)之间的子字符串的开始和结束位置。然后用重复的字符串替换原始字符串的这部分(包括重复编号)。继续,直到到达字符串的结尾

注意事项:

  • 进行替换时,需要更新当前位置,使其现在指向新(修改)字符串中重复字符串的末尾
  • 根据是否允许0重复,您可能需要处理一个空的重复——这是一个空字符串
  • 当到达字符串末尾时,堆栈应为空(所有左括号都与右括号匹配)
  • 堆栈可能在字符串的中间变空了——如果你遇到一个结束括号,输入字符串是畸形的
  • 可能有一种方法可以避开开头/结尾括号,这样它们就不会被视为重复模式的一部分——这取决于您的需求

由于表达式的语法是递归的,我建议使用递归方法

首先将表达式拆分为单个标记。我使用
Regex
来执行此操作并删除空条目

示例:
“5(2(a)sz)”
分为
“5”、“2”、“2”、“a”、“sz”、“sz”、“s”

使用枚举器可以逐个获取令牌。
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 "";
}
公共字符串表达式(字符串表达式)
{
IEnumerator标记=Regex.Split(表达式@“\b”)
。其中(s=>s!=“”)
.GetEnumerator();
if(tokens.MoveNext()){
返回解析(令牌);
}
返回“”;
}
这里的主要工作是以递归的方式完成的

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;
}
私有字符串解析(IEnumerator令牌)
{
字符串s=“”;
while(tokens.Current!=“”){
int n;
如果(tokens.Current==“(”){
if(tokens.MoveNext()){
s+=解析(令牌);
if(tokens.Current==“”){
tokens.MoveNext();
返回s;
}
}
}else if(Int32.TryParse(tokens.Current,out n)){
if(tokens.MoveNext()){
string subExpr=Parse(令牌);
var sb=新的StringBuilder();
对于(int i=0;i
这是我的第二个答案。我的第一个答案是快速回答。在这里,我尝试通过逐个操作来创建解析器

为了转换表达式,您需要对其进行解析。这意味着您必须分析其语法。在分析其语法的同时,您还可以生成输出

1首先要做的是定义所有有效表达式的语法。 在这里,我使用EBNF来实现它。EBNF很简单

{
}
包含重复(可能为零)。
[
]
包含一个可选部分。
|
分离备选方案

有关EBNF的更多详细信息,请参阅WikMedia上的。(此处使用的EBNF变体删除了连接运算符“,”)

EBNF中的语法

Expression = { Term }. Term = [ Number ] Factor. Factor = Text | "(" Expression ")" | Term. 以下字段用于保存令牌信息和布尔值
\u error
,用于告知解析过程中是否发生错误

private IEnumerator<Match> _matches;
TokenType _tokenType;
string _text;
int _number;
bool _error;
3句法和语义分析 现在,我们已经具备了执行实际解析和表达式转换所需的一切。 EBNF到C#代码的转换是直接的,语法中的重复被转换成C#循环语句。 如果将
语句和备选项转换为开关语句,则选项将转换为

// 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();
    }
}
//表达式={Term}。
私有字符串表达式()
{
字符串s=“”;
做{
s+=术语();
}而(_-tokenType!=tokenType.RPar&&u-tokenType!=tokenType.None);
返回s;
}
//术语=[Number]因子。
私有字符串项()
{
int n;
if(_tokenType==tokenType.Number){
n=_数;
如果(!GetToken()){
_错误=真;
返回“错误:预期的因素。”;
}
字符串因子=因子();
如果(_错误){
回报系数;
}
var sb=新的StringBuilder(n*系数长度);
对于(int i=0;iprivate IEnumerator<Match> _matches;
TokenType _tokenType;
string _text;
int _number;
bool _error;
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;
}
// 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();
    }
}