I’ve been looking for things I could do for a code sample and I came across a suggestion. The project is:

A calculator function that takes a single string of input that includes numbers and operators and returns the numeric result of the equation. Don’t forget input validation, error handling (divide by zero), and operator precedence concerns!

So I created something that does this. If the function can’t process the equation it will throw an error. The function is recursive to help take care of parentheses.

PHP

/** processOperator
function to take care of operations.
@param &$numbers array of numbers in string
@param &$operators array of operators in string
@param $operator the operator worked on
*/
function processOperator( &$numbers, &$operators, $operator ) {
$search = array_search( $operator, $operators );
 
while ( $search !== false ) {
    switch ( $operator ) {
    case "^":
        $numbers[ $search ] = ( pow( $numbers[ $search ], $numbers[ $search + 1 ] ) );
        break;
    case "*":
        $numbers[ $search ] = $numbers[ $search ] * $numbers[ $search + 1 ];
        break;
    case "/":
        if ( $numbers[$search + 1] != 0 ) {
            $numbers[$search] = $numbers[$search] / $numbers[$search + 1];
        } else {
            throw new Exception('Division by zero.');
        }
        break;
    case "+":
        $numbers[ $search ] = $numbers[ $search ] + $numbers[ $search + 1 ];
        break;
    case "-":
        $numbers[ $search ] = $numbers[ $search ] - $numbers[ $search + 1 ];
        break;
    }

    unset( $operators[ $search ] );
    unset( $numbers[ $search + 1 ] );

    $operators = array_values( $operators );
    $numbers = array_values( $numbers );

    $search = array_search( $operator, $operators );
    }
}

/**
 * function to take in a equation in the form of a text string and solve
 * doesn't currently account for Parentheses.
 * All values should be seperated by a space
 * @param equation a string of an equation we run to run.
 * @return float of the number of the solved equation
 */
function solveTextString( $equation ) {
    $equation = trim(  $equation );
    $numbers = array( );
    $operators = array( );
    $total = 0;
    $openBraces = 0;
    $pemdas = array('^', '*', '/', '+', '-');

    $openParentheses = substr_count( $equation, "(" );
    $closedParentheses = substr_count( $equation, ")" );

    if ( $openParentheses != $closedParentheses ) {
        throw new Exception('Uneven Parentheses.');
    }

    // Process inner equations
    while ( $openParentheses > 0 ) {
        $open = strpos( $equation, '(');
        $close = null;

        for ( $i =  $open + 1; $i  0) && ($character == ')') ) {
                $openBraces--;
            }
        }

        $innerEquation = substr($equation, $open + 1, ($close - $open ) - 1);
        $innerEquationSolved = solveTextString( $innerEquation );

        $equation = trim( str_replace( "($innerEquation)",  trim($innerEquationSolved), $equation ) );

        --$openParentheses;
    }

    $parts = explode( ' ', trim( $equation ) );

    if ( (count ( $parts ) % 2) == 0 ) { throw new Exception('Invalid Equation'); }

    foreach ( $parts as $key => $part ) {
        if ( !is_numeric( $part ) && ( $key % 2 != 0 ) ) {
               switch( $part ) {
                    case "^":
                    case "*":
                    case "/":
                    case "+":
                    case "-":
                        $operators[] = $part;
                        break;
                    default:
                        throw new Exception('Invalid Equation');
               }
        } elseif ( is_numeric( $part ) && ( $key % 2 == 0 ) ) {
            $numbers[] = ( float )$part;
        } else {
            throw new Exception('Invalid Equation.');
        }
    }

    if ( count ($operators ) >= count ($numbers ) ) {
        throw new Exception('Invalid Equation.');
    }

    for ($i = 0; $i < count( $pemdas ); $i++ ) {
        processOperator( $numbers, $operators, $pemdas[$i] );
    }

    return( $numbers[0] );
}