Reputation: 348
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
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
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
Upvotes: 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
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