Java 用值替换表达式中的各种变量?

Java 用值替换表达式中的各种变量?,java,Java,在Strings中,有变量和数组。例如,s可以是a-(b+a[b[2]])*d+3,这些变量的值存储在单独的文件中。这是我的代码段,我试图用另一个文件中相应的值替换当前字符串s中的任何变量 我只想替换标量变量,而不是数组,我有一个名为scalars的ArrayList,它存储了所有标量变量。因此,对于给定的示例,使用a=1,b=2,d=3,我希望将s变成1-(2+a[b[2]])*3+3标量也不包含重复变量,因此我的代码只适用于单个非重复变量,如a、b、c,而不适用于变量,如varx。如何改进代

在String
s
中,有变量和数组。例如,
s
可以是
a-(b+a[b[2]])*d+3
,这些变量的值存储在单独的文件中。这是我的代码段,我试图用另一个文件中相应的值替换当前字符串
s
中的任何变量

我只想替换标量变量,而不是数组,我有一个名为
scalars
的ArrayList,它存储了所有标量变量。因此,对于给定的示例,使用
a=1
b=2
d=3
,我希望将
s
变成
1-(2+a[b[2]])*3+3
<代码>标量也不包含重复变量,因此我的代码只适用于单个非重复变量,如
a、b、c
,而不适用于变量,如
varx
。如何改进代码以适应各种情况,或者有更好的方法吗

String s = expr; 

    if(scalars.size()>0){
        int j = 0; //make so duplicates can be used , so var can be used, so it doesn't detect arrays
        for(int k = 0; k<s.length(); k++){
            if(Character.isLetter(s.charAt(k))){
                s= s.substring(0,k) + this.scalars.get(j).value + s.substring(k+1,s.length());
                j++;
            }
        }
    }
String s=expr;
if(scalars.size()>0){
int j=0;//make以便可以使用重复项,因此可以使用var,因此它不会检测数组
对于(int k=0;k0){
int j=0;//make以便可以使用重复项,因此可以使用var,因此它不会检测数组
对于(int k=0;k0){
int i;
布尔值foundPlusMinus=false;
对于(i=s.length()-1;i>0;i--){
如果(s.charAt(i)='+'| | s.charAt(i)='-'){
系统输出打印LN(i);
foundPlusMinus=true;
break;//保留子字符串的i值
}
foundPlusMinus=假;
} 
if(foundPlusMinus==false){//for循环已通过,但未找到+或-
对于(i=s.length()-1;i>0;i--){
如果(s.charAt(i)='*'| | s.charAt(i)=='/')){
系统输出打印LN(i);
break;//保留子字符串的i值
}
}
}
String sub1=s.substring(0,i);
系统输出打印项次(sub1);
String sub2=s.substring(i+1,s.length());
系统输出打印LN(sub2);
如果(s.charAt(i)='+'){
tempAns=evalNoPB(sub1)+evalNoPB(sub2);
}如果(s.charAt(i)='-'){
tempAns=evalNoPB(sub1)-evalNoPB(sub2);
}如果(s.charAt(i)='*'){
tempAns=evalNoPB(sub1)*evalNoPB(sub2);
}如果(s.charAt(i)='/'){
浮点除数检查=evalNoPB(sub2);
如果(除数检查!=0){
tempAns=evalNoPB(sub1)/evalNoPB(sub2);
}否则{//不能被0除
抛出新的IllegalArgumentException(“不能除以0”);
}
}
}
返回坦潘;
}  

您需要的是一个编译器,一个相当复杂的程序,它用某种编程语言解析输入并将其转换为另一种编程语言

在这种情况下,输入语言将是带有数字、标量变量、数组变量、和、乘法和括号的表达式。
输出语言应该是带有数字、数组变量、和、乘法和括号的表达式(注意它不包含标量变量)

有很多关于编译器的文献。这是一门跨越计算机科学大学学位课程的学科。
如果你定义了一种非常有限的语言,你可以不使用简单的替换,就像在OP中一样。但是一旦你开始处理更一般的语言,比如长度大于1的变量,你就开始需要整个体系结构来构建编译器

编译器有几个部分:

  • 词法分析器。这会将输入分解为标记。每个标记都是标识符、运算符和类似的东西。词法分析器还会从输入中删除空格
  • 一种语法分析器。一组用标记定义语言的规则。通常用
  • 语义翻译。它可以采用语法分析器中内置的结构,也可以在语法分析器中交织。它将输入语言翻译成输出语言
  • 和一些其他可选部分,一个优化器,这超出了这个问题的范围
  • 词法分析器

    词法分析器将输入分解为标记。
    例如,考虑输入“3 +A”。 预期的令牌为:数字加标识符

    我将用正则表达式定义标记:

    • 加:[+]
    • 减:-
    • 乘法:[*]
    • 划分:/
    • 编号:[0-9]+
    • 标识符:[a-zA-Z]+
    • 开括号:[(]
    • 右括号:[)]
    • 开括号:\[
    • 关闭\u括号:\]
    • EOL:行尾没有正则表达式。输入用尽时,词法分析器将返回此标记
    以下是词法分析器的代码。
    首先是一个令牌类,它包含一个令牌及其类型和从中生成令牌的输入的子字符串

    public class Token
    {
        public static enum TokenType
        {
            PLUS,
            MINUS,
            MULTIPLY,
            DIVIDE,
            NUMBER,
            IDENTIFIER,
            OPEN_PARENTHESIS,
            CLOSE_PARENTHESIS,
            OPEN_BRACKET,
            CLOSE_BRACKET,
            EOL // End of line
        }
    
        public Token( TokenType type, String value)
        {
            this.type = type;
            this.value = value;
        }
    
        private TokenType type;
        public String value;
    
        public TokenType getType()
        {
            return type;
        }
    
        @Override
        public String toString()
        {
            return value;
        }
    }
    
    接下来是词法分析器本身

    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    import expressionparser.Token.TokenType;
    
    class Tokenizer
    {
        private final String input;
        private Matcher matcher;
        private Token lastToken;
    
        public Tokenizer( String input )
        {
            this.input = input;
            Pattern pattern =
                    Pattern.compile( "[+]|-|[*]|/|[0-9]+|[a-zA-Z]+|[(]|[)]|\\[|\\]|[ ]");
            matcher = pattern.matcher( input );
            lastToken = null;
        }
    
        public Token readAndComsumeToken( TokenType type ) throws ExpressionException
        {
            Token result = readToken();
            if ( result.getType()!=type )
                throw new ExpressionException("Erroneous exception" );
            lastToken = null;
            return result;
        }
    
        public Token readToken() throws ExpressionException
        {
            if (lastToken!=null)
                return lastToken;
    
            String value;
            // Read till a non blank is received
            do
            {
                if ( matcher==null )
                {
                    lastToken = new Token(TokenType.EOL, "");
                    return lastToken;
                }
                if ( !matcher.find() )
                  throw new ExpressionException("Erroneous exception" );
                value = matcher.group();
                if ( matcher.end() >= input.length() )
                {
                    // End of String
                    matcher = null;
                }
                if ( value.length()==0 )
                  throw new ExpressionException("Erroneous exception" );
            } while ( value.equals( " " ) ||
                     value.equals("\t") || value.equals("\n") ||
                     value.equals("\f") || value.equals("\r") );
            // Identify read token
            TokenType type;
            if ( value.equals("+") )
                type = TokenType.PLUS;
            else if ( value.equals("-") )
                type = TokenType.MINUS;
            else if ( value.equals("*") )
                type = TokenType.MULTIPLY;
            else if ( value.equals("/") )
                type = TokenType.DIVIDE;
            else if ( value.equals("(") )
                type = TokenType.OPEN_PARENTHESIS;
            else if ( value.equals(")") )
                type = TokenType.CLOSE_PARENTHESIS;
            else if ( value.equals("[") )
                type = TokenType.OPEN_BRACKET;
            else if ( value.equals("]") )
                type = TokenType.CLOSE_BRACKET;
            else
            {
                char firstChar = value.charAt(0);
                if ( firstChar>='0' && firstChar<='9' )
                    type = TokenType.NUMBER;
                else
                    type = TokenType.IDENTIFIER;
            }
            lastToken = new Token( type, value );
            return lastToken;
        }
    
        public void consumeToken() throws IllegalStateException
        {
            if ( lastToken==null )
                throw new IllegalStateException();
            lastToken = null;
        }
    }
    
    有几种方法可以实现这种语法,甚至有工具可以自动实现。
    我将为语法的每一个非终端使用Java方法来实现它。它在语义转换器中呈现,因为它与解析器交织在一起

    语义翻译。

    ExpressionParser
    是语法分析器和语义转换器的组合。它使用
    Tokenizer
    进行词法分析

    import expressionparser.Token.TokenType;
    import java.util.List;
    
    public class ExpressionParser
    {
        private Tokenizer lex;
        private List<Scalar> scalars;
    
        public String compile( String expression, List<Scalar> scalars ) throws ExpressionException
        {
            lex = new Tokenizer(expression);
            this.scalars = scalars;
            return evalWholeExpression();
        }
    
        private String evalWholeExpression( ) throws ExpressionException
        {
            String result = evalExpression();
            lex.readAndComsumeToken(Token.TokenType.EOL);
            return result;
        }
    
        private String evalExpression() throws ExpressionException
        {
            String left = evalSummand();
            return evalTailSum( left );
        }
    
        private String evalSummand( ) throws ExpressionException
        {
            String left = evalFactor();
            return evalTailMultiplication( left );
        }
    
        private String evalFactor() throws ExpressionException
        {
            Token token = lex.readToken();
            if ( token.getType() == TokenType.OPEN_PARENTHESIS )
            {
                lex.consumeToken();
                String result = evalExpression();
                lex.readAndComsumeToken(TokenType.CLOSE_PARENTHESIS);
                return "(" + result + ")";
            }
            else if ( token.getType() == TokenType.NUMBER )
            {
                lex.consumeToken();
                return token.toString();
            }
            else if ( token.getType()==TokenType.IDENTIFIER )
            {
                lex.consumeToken();
                String tailArray = evalTailArray();
                if ( "".equals(tailArray) )
                {
                    String scalarValue = evaluateScalar( token.toString() );
                    return scalarValue;
                }
                else
                {
                    verifyIsNotScalar( token.toString() );
                    return token + tailArray;
                }
            }
            else
                throw new ExpressionException( "Incorrect expression" );
        }
    
        private String evalTailSum( String left ) throws ExpressionException
        {
            Token token = lex.readToken();
            if ( token.getType()==TokenType.PLUS )
            {
                lex.consumeToken();
                String right = evalSummand();
                return evalTailSum( left + "+" + right );
            }
            else if ( token.getType()==TokenType.MINUS )
            {
                lex.consumeToken();
                String right = evalSummand();
                return evalTailSum( left + "-" + right );
            }
            else
                return left;
        }
    
        private String evalTailMultiplication( String left ) throws ExpressionException
        {
            Token token = lex.readToken();
            if ( token.getType()==TokenType.MULTIPLY )
            {
                lex.consumeToken();
                String right = evalFactor();
                return evalTailSum( left + "*" + right );
            }
            else if ( token.getType()==TokenType.DIVIDE )
            {
                lex.consumeToken();
                String right = evalFactor();
                return evalTailSum( left + "/" + right );
            }
            else
                return left;
        }
    
        private String evalTailArray() throws ExpressionException
        {
            Token token = lex.readToken();
            if ( token.getType() == TokenType.OPEN_BRACKET )
            {
                lex.consumeToken();
                String result = evalExpression();
                lex.readAndComsumeToken(TokenType.CLOSE_BRACKET);
                return "[" + result + "]" + evalTailArray();
            }
            else
                return "";
        }
    
        private String evaluateScalar( String text ) throws ExpressionException
        {
            assert text!=null;
            for ( Scalar s : scalars )
            {
                if ( text.equals( s.identifier ) )
                    return "" + s.value;
            }
            throw new ExpressionException( "Incorrect expression" );
        }
    
        private void verifyIsNotScalar( String text ) throws ExpressionException
        {
            assert text!=null;
            for ( Scalar s : scalars )
            {
                if ( text.equals( s.identifier ) )
                    throw new ExpressionException( "Incorrect expression" );
            }
        }
    
    }
    
    由其自身和本规则使用:

    <tailSum>            ::= PLUS <summand> <tailSum> |
                             MINUS <summand> <tailSum> |
                             ""
    
    <expression>         ::= <summand> <tailSum>
    
    在标识符分支中,根据上下文无关语法中的规则,使用标识符并调用
    evalTailArray

    evalTailArray
    如果没有数组订阅,则返回空字符串,因此标识符必须是标量变量。在这种情况下,它调用
    evaluateScalar<tailSum>            ::= PLUS <summand> <tailSum> |
                             MINUS <summand> <tailSum> |
                             ""
    
    <expression>         ::= <summand> <tailSum>
    
    public class Scalar
    {
        public Scalar( String identifier, int value )
        {
            this.identifier = identifier;
            this.value = value;
        }
        public final String identifier;
        public final int value;
    }
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class Main
    {
        public static void main(String[] args)
        {
            try
            {
                final List<Scalar> scalars = new ArrayList<>();
                scalars.add( new Scalar( "a", 1 ) );
                scalars.add( new Scalar( "b", 2 ) );
                scalars.add( new Scalar( "d", 3 ) );
                scalars.add( new Scalar( "varx", 5  ) );
    
                ExpressionParser parser = new ExpressionParser();
    
                System.out.println( parser.compile("a - (b+A[B[2]])*d + 3", scalars));
                System.out.println( parser.compile("5*(2+varx)+a", scalars));
                System.out.println( parser.compile("B[a*384+(5+(5*(varx+3)))]+varx", scalars));
                System.out.println( parser.compile("34+", scalars ) );
            }
            catch (ExpressionException ex)
            {
                System.out.println( ex.getMessage() );
            }
        }
    }
    
    1-(2+A[B[2]])*3+3
    5*(2+5)+1
    B[1*384+(5+(5*(5+3)))]+5
    Incorrect expression