Ekane 3
Ekane 3

Reputation: 348

Matching parenthesis in PHP

I want to find if a string of parenthesis matches using php. So I wrote this.

<?php  

function Parenthesis($string) {
$ok = preg_match('~(\((?1)*+\)|\[(?1)*+]|{(?1)*+})*\z~A', $string);
if ($ok==1) {
    return "true"; 
} else {
    return "false";
}
}

$entree = "{([]){}()}";
$sortie = Parenthesis($entree);
echo "Réponse : ".$sortie;

And it gives true.

But when I pass $entree = "{C{}[{[a]}RqhL]{y2}}"; it gives false, meanwhile I need true. How can I modify the code.

Upvotes: 0

Views: 1940

Answers (4)

Sarang
Sarang

Reputation: 784

function isBalanced($s) {
    $compareStack = array('('=>')','['=>']','{'=>'}');
    $individualElement = splitString($s);
    $stack = array();
    foreach($individualElement as $key => $value) {
        if(array_key_exists($value, $compareStack)) {
            array_push($stack,$value);
        } else {
            $remove = end($stack);
            if(empty($remove)) {
                return 'NO';
                break;
            }
            if($compareStack[$remove] == $value) {
                array_pop($stack);
            } else {
                return 'NO';
                break;
            }
        }
    }
    if(empty($stack)) {
        return 'YES';    
    } else {
        return 'NO';
    }   
}

The input parameter $s is the string.
e.g.

'{([])}' will return YES
'{((])}' will return NO

Upvotes: 0

Nick
Nick

Reputation: 147146

This is probably more easily (and robustly) done by parsing the string a character at a time and maintaining a stack of the opening parentheses. When a closing parenthesis is seen, the top of the stack (the last seen opening parenthesis) is popped to verify that it matches the closing parenthesis. If the stack is empty, or the parentheses do not match, we return false. Once all characters have been parsed, a match is indicated by the stack being empty.

function Parenthesis($string) {
    $opening = array('}' => '{', ']' => '[', ')' => '(');
    $parens = array();
    foreach (str_split($string) as $char) {
        switch ($char) {
            case '{':
            case '[':
            case '(':
                $parens[] = $char;
                break;
            case '}':
            case ']':
            case ')':
                if (!count($parens) || array_pop($parens) != $opening[$char]) return false;
                break;
            default:
                break;
        }
    }
    return count($parens) === 0;
}

function check_balanced($string) {
    echo "$string is " . (Parenthesis($string) ? '' : 'not ') . "balanced\n";
}

check_balanced("{([]){}()}");
check_balanced("{C{}[{[a]}RqhL]{y2}}");
check_balanced("{([]){]()}");

Output:

{([]){}()} is balanced
{C{}[{[a]}RqhL]{y2}} is balanced
{([]){]()} is not balanced

Demo on 3v4l.org

Upvotes: 3

Ekane 3
Ekane 3

Reputation: 348

Finally figured something out.

function isParenthesis(string $expression){
        $patterns = array('{','}','(',')','[',']');
        $occ = array(0,0,0,0,0,0);

        for($i = 0; $i < strlen($expression); $i++){
            for($j = 0; $j < count($patterns); $j++){
                if($expression[$i] == $patterns[$j]){
                    $occ[$j]++;
                }
            }
        }
        for ($i=0; $i < count($occ); $i+=2) { 
            if($occ[$i] != $occ[$i+1]){
                return 0;
            }
        }
        return 1;
    }

    $str = "{[{iHTSc}]}p(R)m(){q({})";
    echo "l'expression ".$str." est correcte ? : ".isParenthesis($str);

And it works greatly ! Thanks for your contributions.

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626747

The regex you are after is long and really hard to maintain. If there must be at least one pair of brackets in the string, this is the pattern you need:

\A[^][(){}]*+(?:(?:(\((?:[^()]++|(?1))*\))|(\[(?:[^][]++|(?2))*])|({(?:[^{}]++|(?3))*}))[^][(){}]*+)++\z

See the regex demo.

NOTE: If the string can have no brackets/braces, you should replace the ++ at the end with *+ (zero or more occurrences).

Details

  • \A - start of string
  • [^][(){}]*+ - zero or more chars other than ], [, (, ), { and }
  • (?:(?:(\((?:[^()]++|(?1))*\))|(\[(?:[^][]++|(?2))*])|({(?:[^{}]++|(?3))*}))[^][(){}]*+)++ - one or more occurrences of
    • (?:(\((?:[^()]++|(?1))*\))|(\[(?:[^][]++|(?2))*])|({(?:[^{}]++|(?3))*})) - one of the three alternatives:
      • (\((?:[^()]++|(?1))*\))| - substring between nested ( and ) round brackets (parentheses), or
      • (\[(?:[^][]++|(?2))*])| - substring between nested [ and ] square brackets, or
      • ({(?:[^{}]++|(?3))*}) - substring between nested braces, { and }
    • [^][(){}]*+ - zero or more chars other than ], [, (, ), { and }
  • \z - the very end of string.

Upvotes: 1

Related Questions