如何动态地将括号添加到布尔表达式?

时间:2015-06-08 20:54:44

标签: java

我用Java编写一个程序,它应该作为布尔表达式的真值表生成器。但是,我在方括号方面遇到了很多麻烦。当一对括号括起整个表达式(产生运行时错误),或者表达式中没有足够的括号(产生错误的结果)时,错误开始。

这是我的所有代码:

        import javax.swing.*;
        import java.awt.*;
        import java.awt.event.*;
        import java.util.*;
        import java.lang.Math;

        public class BooleanAlgebra
        {
           public static void main(String[] args)
           {
              new BooleanAlgebra();
           }

           private JFrame frame;
           private JPanel panel;
           private JTextField textField;
           private JButton and;
           private JButton or;
           private JButton not;
           private JButton nor;
           private JButton nand;
           private JButton xor;
           private JButton xnor;
           private JPanel panel2;
           private JButton generate;
           private JButton close;
           private ArrayList<Character> variables;
           private char[] chars;

           public BooleanAlgebra()
           {
              frame = new JFrame("Boolean Algebra");
              frame.setSize(new Dimension(800, 800));
              textField = new JTextField("(x+y)");

              and = new JButton("AND   [ x & y ]");
              or = new JButton("OR   [ x + y ]");
              not = new JButton("NOT   [ ! x ]");
              nor = new JButton("NOR   [ ! ( x + y ) ]");
              nand = new JButton("NAND   [ ! ( x & y ) ]");
              xor = new JButton("XOR   [ ( x & ! y ) + ( ! x & y ) ]");
              xnor = new JButton("XNOR   [ ( x & y ) + ( ! x & ! y ) ]");
              generate = new JButton("Generate Table");
              close = new JButton("Exit");

              ButtonHandler buttons = new ButtonHandler();
              and.addActionListener(buttons);
              or.addActionListener(buttons);
              not.addActionListener(buttons);
              nor.addActionListener(buttons);
              nand.addActionListener(buttons);
              xor.addActionListener(buttons);
              xnor.addActionListener(buttons);
              generate.addActionListener(buttons);
              close.addActionListener(buttons);

              panel2 = new JPanel();
              panel2.setLayout(new GridLayout(1, 2));
              panel2.add(generate);
              panel2.add(close);

              panel = new JPanel();
              panel.setLayout(new GridLayout(9, 1));
              panel.add(textField);
              panel.add(and);
              panel.add(or);
              panel.add(not);
              panel.add(nor);
              panel.add(nand);
              panel.add(xor);
              panel.add(xnor);
              panel.add(panel2);

              frame.add(panel);
              frame.setLocationRelativeTo(null);
              frame.setVisible(true);
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           }

           private boolean isLetter(char a)
           {
              if((a > 64 && a < 91) || (a > 96 && a < 123))
              {
                 return true;
              }
              return false;
           }

           private void generate()
           {
              chars = ("(" + textField.getText() + ")").toCharArray();
              variables = new ArrayList<Character>();

              for(int i = 0; i < chars.length; i++)
              {
                 if(isLetter(chars[i]))
                 {
                    if(!variables.contains(chars[i]))
                    {
                       variables.add(chars[i]);
                    }
                 }
              }

              Collections.sort(variables);
              String[] heads = new String[variables.size() + 1];
              for(int i = 0; i < heads.length - 1; i++)
              {
                 heads[i] = variables.get(i).toString();
              }
              heads[heads.length - 1] = textField.getText();

              int row = (int)Math.pow(2, variables.size());
              int column = variables.size() + 1;
              int count = 0;
              int max = 1;
              Integer[][] array = new Integer[row][column];

              for(int a = column - 2; a >= 0; a--)
              {
                 for(int b = 0; b < row; b++)
                 {
                    if(count < max)
                    {
                       array[b][a] = 0;
                       count++;
                    }
                    else if(count >= max)
                    {
                       array[b][a] = 1;
                       count++;
                       if(count == max * 2)
                       {
                          count = 0;
                       }
                    }
                 }
                 max = max * 2;
              }

              for(int i = 0; i < row; i++)
              {
                 array[i][column - 1] = 0;
              }

              int[][] arrayCopy = new int[row][column];
              for(int i = 0; i < row; i++)
              {
                 for(int j = 0; j < column; j++)
                 {
                    arrayCopy[i][j] = array[i][j];
                 }
              }
              for(int i = 0; i < row; i++)
              {
                 array[i][column - 1] = calculate(arrayCopy[i]);
              }

              JTable table = new JTable(array, heads);
              JFrame frame2 = new JFrame(textField.getText());
              frame2.add(new JScrollPane(table));
              frame2.pack();
              frame2.setVisible(true);
              table.setEnabled(false);
           }

           private int calculate(int[] array)
           {
              Stack<Character> ops  = new Stack<Character>();
              Stack<Integer> values = new Stack<Integer>();

              for(int i = 0; i < chars.length; i++)
              {
                 char s = chars[i];
                 if      (s == '(')               ;
                 else if (s == '+')    ops.push(s);
                 else if (s == '&')    ops.push(s);
                 else if (s == '!')    ops.push(s);
                 else if (s == ')')
                 {
                    char operation = ops.pop();
                    int v = values.pop();
                    if      (operation == '+')    v = or(values.pop(), v);
                    else if (operation == '&')    v = and(values.pop(), v);
                    else if (operation == '!')    v = not(v);
                    values.push(v);
                 }
                 else if(isLetter(s))
                 {
                    values.push(array[variables.indexOf(s)]);
                 }
              }
              return values.pop();
           }

           private int and(int a, int b)
           {
              if(a == 1 && b == 1)
              {
                 return 1;
              }
              return 0;
           }

           private int or(int a, int b)
           {
              if(a == 0 && b == 0)
              {
                 return 0;
              }
              return 1;
           }
           private int not(int a)
           {
              if(a == 1)
              {
                 return 0;
              }
              return 1;
           }

           public class ButtonHandler implements ActionListener
           {
              public void actionPerformed(ActionEvent event)
              {
                 if(event.getSource() == and)
                 {
                    textField.setText(textField.getText() + "(x&y)");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == or)
                 {
                    textField.setText(textField.getText() + "(x+y)");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == not)
                 {
                    textField.setText(textField.getText() + "(!x)");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == nor)
                 {
                    textField.setText(textField.getText() + "!(x+y)");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == nand)
                 {
                    textField.setText(textField.getText() + "!(x&y)");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == xor)
                 {
                    textField.setText(textField.getText() + "(x&(!y))+(((!x)&y))");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == xnor)
                 {
                    textField.setText(textField.getText() + "(x&y)+(((!x)&(!y)))");
                    textField.requestFocus(true);
                 }
                 if(event.getSource() == generate)
                 {
                    generate();
                 }
                 if(event.getSource() == close)
                 {
                    System.exit(0);
                 }
              }
           }
        }

我需要帮助才能完成这项工作而无需用户自己正确输入括号(我希望程序能够修复表达式,或以某种方式评估它而不必像我在这里那样等待一个紧密的括号。)

要测试代码并查看错误,请在运行时输入以下内容:

 (x+y) --> runtime error because brackets surround the whole expression
 x+y+z --> incorrect output table
 x+y   --> works
 x&y   --> works
 !!x   --> incorrect output table

请向我解释一下。谢谢!

1 个答案:

答案 0 :(得分:1)

generate方法中,您声明了以下内容:

chars = ("(" + textField.getText() + ")").toCharArray();

但是,从您的GUI实际上有一个带括号的条目,例如(x+y),它基本上将chars的值更改为((x+y))

calculate中,您会在关闭)字符时弹出,第二个大括号返回EmptyStackException。如果你从一般的文本字段或从上面引用的行中删除大括号应该打印出来。

关于(!!x)处的输入失败:如果有多个可用操作,则只从堆栈中弹出一个操作而忽略。

当您询问如何解决您的问题时,只使用了一个运算符:

您可以尝试将类似a && b || (c && d) && !e的等式细分为自己的细分,并评估每个术语,并将最后的所有这些术语组合成类似于an earlier post I did的结果,该结果提供了一个简单的规则引擎普通的Java。但请注意,我不保证绑定强度的正确性,也没有在此示例中包含大括号 - 因此它只是规则引擎的一个非常基本的演示!

关注OO principley,您可以创建一个Expression课程AndOrNotTerm,...是...的子项一种boolean evaluate()方法,它将调用传播到相应的术语及其绑定。 因此,上面的等式可以用更类似于此方法的代码来表示:

Expression terms = new Or(
    new And(new Term("a", ...), new Term("b", ...)), 
    new And(new Term("c", ...), 
        new And(new Term("d", ...), new Not(new Term("e", ...))
    )
);
boolean value = terms.evaluate();

要获得类似上面的结构,你基本上从一个空堆栈开始,并从等式迭代所有标记。堆栈将保存当前打开的表达式。因此,您首先检索第一个字符并确定它是操作数((还是!)还是字母。如果找到了表达式,则可以为其创建新的类表示并将其添加到堆栈中,否则根据该字母创建一个术语对象,并指定相应的array[variables.indexOf(s)]值,该值为0或1(false或true)到了这个词。

然后检查堆栈上是否有元素(peek将返回堆栈中最顶层的元素而不删除它),如果是,则将该术语添加到操作数,否则将其临时存储,以便将其添加到你点击操作数然后添加它。如果操作数的所有字段都已填满,则需要从堆栈中弹出它并将其(如果尚未完成)分配给堆栈中新的最顶层元素。这样就可以实现嵌套结构。

但是,您还必须考虑操作的绑定顺序。支撑比手术更强大,并且比手术更强烈地结合。因此,在命中新操作时,如果绑定顺序强于当前元素的绑定顺序,则还需要检查堆栈中最顶层的元素。 F.E.当从上面迭代示例时,堆栈当前包含Anda的{​​{1}}操作,我们当前正在处理b操作。由于这个绑定比Or弱,我们需要从堆栈中弹出这个元素并将其分配给And操作的左元素并将其推送到堆栈。

这与大括号类似。但是,它们可以包含多个表达式,只有在解析了右括号时才需要从堆栈中弹出。

我希望这能让您有足够的见解继续您的旅程。