Search code examples
javabooleanboolean-logicboolean-expression

How can I validate a boolean string input in java


I've been fighting with this problem and haven't found a solution. I have to validate the syntax of a boolean string expression so I can use it to find words or sentences in a document. For example, (footballer football !| basket)( should be incorrect because footballer and football are separated and should be between "" , and also because of the incorrect parenthesis and the ! |that makes no sense. But ("footballer football" | ! basket) should be correct. It is a simple bool expression so I can use &,!, |, ()... Any idea?

I've tried to iterate over the string trying to validate every single character but I can't get to the final solution.


Solution

  • This may not be an overall solution but it might give you a step towards that goal. The method below will try to parse and validate the supplied custom expressions you described in your post. If the supplied expression is valid the components of that supplied expression is returned within a String[] Array. If the returned String[] Array is null then the supplied expression is found to be invalid. An Invalid expression will also display an error message within the console window explaining why that expression is invalid. Be sure to read the comments in code:

    /**
     * Custom Expression Parser/Validator:
     * 
     * If the supplied expression is valid whereas it meets the guidelines within 
     * the code, then return a String[] Array containing the components of that 
     * expression. If the expression is found to be invalid then a warning message 
     * is displayed to the Console Window explaining the problem and null is returned.
     * 
     * @param expressionString (String) The expression to validate.<br>
     * 
     * @return (String[] Array) Returns null if the expression is found invalid 
     * otherwise the returned String Array will contain the components of the 
     * expression. Process these returned expression components as you see fit.
     */
    public String[] isExpressionValid(String expressionString) {
        // List to hold expression components.
        List<String> expressionList = new ArrayList<>();
        
        // If the expression string is null or empty then return null.
        if (expressionString == null || expressionString.isEmpty()) {
            return null;
        }
        
        // Are the brackets proper in the expression?
        Map<Character, Character> openClosePair = new HashMap<>();
        openClosePair.put(')', '(');
        Stack<Character> stack = new Stack<>();
        for (char ch : expressionString.toCharArray()) {
            if (openClosePair.containsKey(ch)) {
                if (stack.isEmpty() || !Objects.equals(stack.pop(), openClosePair.get(ch))) {
                    break;
                }
            }
            else if (openClosePair.values().contains(ch)) {
                stack.push(ch);
            }
        }
        if (!stack.isEmpty()) {
            System.err.println("Invalid Expression! [" + expressionString + "] -  Parentheses Mismatch!");
            return null;
        }
        
        /* Parentheses are valid so now remove them to validate 
           the data within the parentheses.    */
        expressionString = expressionString.replaceAll("[\\(\\)]", "");
        
        /* Is &, !, or | within the expression? If so, is it proper?
           If there are consecutive `same` operators (ie: "&&&") then
           convert them to a single operator (ie: "&").        */
        expressionString = expressionString.replaceAll("[&]{2,}", "&")
                .replaceAll("[|]{2,}", "|"). replaceAll("[!]{2,}", "!");
        
        // Add whatever you feel would be invalid...
        String[] invalidOperators = {"&|", "|&", "!|", "!&", "!&|", "!|&", 
                                     "&!|", "&|!", "|!&", "|&!"};
        // Make sure of valid operator use.
        for (String op : invalidOperators) {
            if (expressionString.contains(op)) {
                System.err.println("Invalid Logical Operator Configuruation [" + 
                                   op + "] Within Expression!");
                return null;
            }
        }
        
        /* Split the expression on delimiters '&' or '|' but 
           also add the delimiter to the generated array: */
        String regEx = "((?<=\\Q&\\E)|(?=\\Q&\\E))|"
                     + "((?<=\\Q|\\E)|(?=\\Q|\\E))";
        String[] expParts = expressionString.split(regEx);
        String exp;
        for (int i = 0; i < expParts.length; i++) {
            exp = expParts[i].trim();  // Remove leading/trailing whitespaces.
            // Is the element a non-numerical value?
            if (!exp.matches("-?\\d+(\\.\\d+)?") && !exp.matches("[!\\|&]")) {
                // This element must be alpha or alphanumeric. 
                /* Is there a whitespace in it? If so, is it wrapped in quote marks? 
                   If not then this is invalid.                */
                if (exp.contains(" ") && ((!exp.startsWith("!\"") || !exp.startsWith("\"")) && !exp.endsWith("\""))) {
                    System.err.println("Invalid String [" + exp + "] Within Expression!" 
                            + System.lineSeparator() + "Because this portion of the expression "
                            + "contains at least one whitespace," + System.lineSeparator() 
                            + "it should be wrapped within quotation marks excluding any Logical Operator" 
                            + System.lineSeparator() + "located at the beginning.");
                    return null;
                }
            }
            /* Does the expression start with or end with a Logical Operator '&' or '|'? 
               This is considered invalid.            */
            if ((i == 0 || i == expParts.length - 1) && (exp.equals("&") || exp.equals("|"))) {
                System.err.println("Invalid Logical Operator Location! [" + expressionString + "]"
                            + System.lineSeparator() + "The expression can not start with or end "
                            + "with a '&' or '|' operator!");
                return null;        
            }
            
            // Add the expresion component to the List
            expressionList.add(exp);
        }
        
        // Convert the List to a String[] Array and return.
        return expressionList.toArray(new String[expressionList.size()]);
    }
    

    How you might use the above method would be something like this:

    String expression = "(footballer football !| basket)(";
        
    String[] expressionParts = isExpressionValid(expression);
    
    if (expressionParts != null) {
        // Display the components of the supplied expression:
        System.out.println(Arrays.toString(expressionParts));
    }