如何将字符串转换为代数表达式

How to turn a String into a Algebraic Expression

所以我正在尝试编写一个程序来获取像 3x^2 + x + 8 这样的函数,然后绘制该函数的图形。我正在使用 eval() 方法将 String 转换为表达式,但它一直抛出 NullPointerException。

package Function;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JFrame;

public class FunctionGrapherTest 
{
public static void main(String[] args)
{
    JFrame frame = new JFrame();

    FunctionGrapherComponent comp = new FunctionGrapherComponent();
    frame.setSize(600, 600);

    frame.setTitle("Function");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);

    frame.add(comp);
    frame.getContentPane().add(comp.control(), BorderLayout.SOUTH);

    Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (int)((dimension.getWidth() - frame.getWidth()) / 2);
    int y = (int)((dimension.getHeight() - frame.getHeight()) / 2);
    frame.setLocation(x, y);
}
}

package Function;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

public class FunctionGrapherComponent extends JPanel
{
private static final long serialVersionUID = 1L;
public FunctionGrapherComponent()
{
    JPanel field = new JPanel();

    JLabel y = new JLabel("y = ", SwingConstants.RIGHT);
    field.add(y);
    equaField = new JTextField(15);
    field.add(equaField);

    control = new JPanel();
    control.setLayout(new GridLayout(1, 3));

    control.add(field);
    JButton draw = makeButton("Graph");
    control.add(draw);

    count = 0;
}
public JPanel control()
{
    return control;
}
public JButton makeButton(String label)
{
    JButton button = new JButton(label);
    class ButtonListener implements ActionListener
    {
        public void actionPerformed(ActionEvent event)
        {
            String equation = equaField.getText();
            if(!equation.equals("") || equation != null)
            {
                equa = equation;
                count = 1;
                repaint();
            }       
            equaField.setText("");
        }
    }
    ActionListener listener = new ButtonListener();
    button.addActionListener(listener);
    return button;
}
public void paintComponent(Graphics g)
{
    super.paintComponent(g);
    Graphics2D g2 = (Graphics2D)g;
    Axes axes = new Axes(xPixel(XMIN), xPixel(XMAX), yPixel(YMIN), yPixel(YMAX),
            xPixel(0), yPixel(0), sWidth(1), sHeight(1));
    axes.drawAxes(g2);
    axes.drawTicks(g2);

    if(count == 1)
    {
        Function func = new Function();
        delta = (XMAX - XMIN) / 100;
        for(double i = XMIN; i <= (XMAX - delta); i = i + delta)
        {
            x1 = xPixel(i);
            y1 = yPixel(func.functionVal(i, equa));
            x2 = xPixel(i + delta);
            y2 = yPixel(func.functionVal(i + delta, equa));
            func.plot(g2, x1, y1, x2, y2);
        }
        count = 0;
    }
}
public double xPixel(double xuser)                      
{
    return (xuser - XMIN) * (getWidth( ) - 1) / (XMAX - XMIN);
}
public double yPixel(double yuser)
{
   return (yuser - YMAX) * (getHeight( ) - 1) / (YMIN - YMAX);
}
public double sHeight(double yuser)
{
   return yuser * (getHeight() - 1) / (YMAX - YMIN);
}
public double sWidth(double xuser)
{
   return xuser * (getWidth() - 1) / (XMAX - XMIN);
}
private static final double XMIN = -100;        
private static final double XMAX = 100;
private static final double YMIN = -100;
private static final double YMAX = 100;
private double delta;
private double x1;
private double y1;
private double x2;
private double y2;
private int count;
private JPanel control;
private JTextField equaField;
private String equa;
}


package Function;

import java.awt.Graphics2D;
import java.awt.geom.Line2D;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class Function
{
public Function()
{

}
public void plot(Graphics2D g2, double x1, double y1, double x2, double y2) 
{
    Line2D.Double seg = new Line2D.Double(x1, y1, x2, y2);
    g2.draw(seg);
}
public double functionVal(double x, String equa)
{
    ScriptEngineManager mgr = new ScriptEngineManager();
    ScriptEngine engine = mgr.getEngineByName("Java"); 
    try 
    {
        funcVal = (double)engine.eval(equa);
    } 
    catch (ScriptException e) 
    {}
    return funcVal;
}
private double funcVal;
}


package Function;

import java.awt.Graphics2D;
import java.awt.geom.Line2D;

public class Axes
{
public Axes(double xmin, double xmax, double ymin, double ymax,
        double xzero, double yzero, double xunit, double yunit)
{
    xMin = xmin;
    xMax = xmax;
    yMin = ymin;
    yMax = ymax;
    xZero = xzero;
    yZero = yzero;
    xUnit = xunit;
    yUnit = yunit;
}
public void drawAxes(Graphics2D g2) 
{
    Line2D.Double xAxis = new Line2D.Double(xMin, yZero, xMax, yZero);
    Line2D.Double yAxis = new Line2D.Double(xZero, yMin, xZero, yMax);
    g2.draw(xAxis);
    g2.draw(yAxis);
}
public void drawTicks(Graphics2D g2)
{
    for(double i = xZero + xUnit; i <= xMax; i = i + xUnit)
    {
        Line2D.Double tick = new Line2D.Double(i, yZero + TICK_LENGTH, i,      yZero - TICK_LENGTH);
        g2.draw(tick);
    }
    for(double i = xZero - xUnit; i >= xMin; i = i - xUnit)
    {
        Line2D.Double tick = new Line2D.Double(i, yZero + TICK_LENGTH, i, yZero - TICK_LENGTH);
        g2.draw(tick);
    }
    for(double i = yZero + yUnit; i <= yMin; i = i + yUnit)
    {
        Line2D.Double tick = new Line2D.Double(xZero + TICK_LENGTH, i, xZero - TICK_LENGTH, i);
        g2.draw(tick);
    }
    for(double i = yZero - yUnit; i >= yMax; i = i - yUnit)
    {
        Line2D.Double tick = new Line2D.Double(xZero + TICK_LENGTH, i, xZero - TICK_LENGTH, i);
        g2.draw(tick);
    }
}
private double xMin;    
private double xMax;
private double yMin;
private double yMax;
private double xZero;
private double yZero;
private double xUnit;
private double yUnit;
private static final double TICK_LENGTH = 3;
}

首先将 ScriptEngine engine = mgr.getEngineByName("Java"); 更改为 ScriptEngine engine = mgr.getEngineByName("javascript");,尽管有些人认为 Java 不是脚本语言,Java 和 Java脚本

此外,您不应该忽略 engine...

抛出的异常
try {
    System.out.println(equa);
    funcVal = ((Number) engine.eval(equa)).doubleValue();
} catch (ScriptException e) {
    e.printStackTrace();
}

如果您不在每次调用 functionVal

时重新创建 ScriptEngine,您也会发现它更快
public static class Function {
    private final ScriptEngine engine;

    public Function() {
        ScriptEngineManager mgr = new ScriptEngineManager();
        engine = mgr.getEngineByName("javascript");
    }

    public void plot(Graphics2D g2, double x1, double y1, double x2, double y2) {
        Line2D.Double seg = new Line2D.Double(x1, y1, x2, y2);
        g2.draw(seg);
    }

    public double functionVal(double x, String equa) {
        try {
            System.out.println(equa);
            funcVal = ((Number) engine.eval(equa)).doubleValue();
        } catch (ScriptException e) {
        }
        return funcVal;
    }
    private double funcVal;
}

已更新

所以,假设你想解方程 3x^2 + x + 8,你需要给 x 一些值...

engine.put("x", 10);

然后你可以使用 3*2^+x+8 作为你的等式...

funcVal = ((Number) engine.eval("3*2^+x+8")).doubleValue();

例如...

    public double functionVal(double x, String equa) {
        try {
            System.out.println(equa);
            engine.put("x", 10);
            funcVal = ((Number) engine.eval(equa)).doubleValue();
            System.out.println(equa + " = " + funcVal);
        } catch (ScriptException e) {
            e.printStackTrace();
        }
        return funcVal;
    }