寻求匹配并移除未闭合括号的PHP正则表达式解决方案
移除PHP字符串中未闭合的括号
问题分析
你之前使用的正则\((?:[^)(]*(?R)?)*+\)只能匹配完全闭合的嵌套圆括号,既无法处理方括号[],也无法定位并移除未闭合的孤立括号,因此达不到预期效果。要同时处理()和[]的未闭合场景,采用栈遍历的方法逻辑更清晰、结果更可靠。
栈实现方案
通过栈跟踪括号的嵌套状态,准确标记有效闭合的括号,移除未匹配的孤立括号:
function removeUnclosedBrackets(string $str): string { $bracketPairs = ['(' => ')', '[' => ']']; $reversePairs = array_flip($bracketPairs); $stack = []; $keep = array_fill(0, strlen($str), true); foreach (str_split($str) as $index => $char) { // 遇到左括号,入栈记录位置与类型 if (isset($bracketPairs[$char])) { $stack[] = ['index' => $index, 'type' => $char]; } // 遇到右括号,匹配栈顶的左括号 elseif (isset($reversePairs[$char])) { $matched = false; // 从栈顶往前找匹配的左括号,清理不匹配的左括号 for ($i = count($stack) - 1; $i >= 0; $i--) { if ($stack[$i]['type'] === $reversePairs[$char]) { array_splice($stack, $i, 1); $matched = true; break; } else { $keep[$stack[$i]['index']] = false; array_splice($stack, $i, 1); } } // 无匹配左括号,标记当前右括号为移除项 if (!$matched) { $keep[$index] = false; } } } // 栈中剩余的左括号均为未闭合项,标记移除 foreach ($stack as $item) { $keep[$item['index']] = false; } // 过滤移除项,生成结果 $result = ''; foreach (str_split($str) as $index => $char) { if ($keep[$index]) { $result .= $char; } } return $result; } // 测试示例 $test1 = "A Pro Webcam ((Good text) [[Good Text] more texts"; $test2 = "Text (Example (Good text) [Good Text] more texts"; echo removeUnclosedBrackets($test1) . PHP_EOL; // 输出: A Pro Webcam (Good text) [Good Text] more texts echo removeUnclosedBrackets($test2) . PHP_EOL; // 输出: Text Example (Good text) [Good Text] more texts
正则辅助方案(适合无交叉嵌套场景)
如果你的字符串不存在([)]这类交叉嵌套的括号,也可以用递归正则先保留闭合结构,再移除孤立括号:
function removeUnclosedBracketsRegex(string $str): string { $parenCache = []; // 处理圆括号 while (preg_match('/\((?:[^()]|(?R))*\)/', $str)) { $str = preg_replace_callback('/\((?:[^()]|(?R))*\)/', function($match) use (&$parenCache) { static $counter = 0; $key = "{PAREN_$counter}"; $parenCache[$key] = $match[0]; $counter++; return $key; }, $str); } $str = preg_replace('/[()]/', '', $str); foreach ($parenCache as $key => $value) { $str = str_replace($key, $value, $str); } // 处理方括号 $parenCache = []; while (preg_match('/\[(?:[^[\]]|(?R))*\]/', $str)) { $str = preg_replace_callback('/\[(?:[^[\]]|(?R))*\]/', function($match) use (&$parenCache) { static $counter = 0; $key = "{BRACKET_$counter}"; $parenCache[$key] = $match[0]; $counter++; return $key; }, $str); } $str = preg_replace('/[\[\]]/', '', $str); foreach ($parenCache as $key => $value) { $str = str_replace($key, $value, $str); } return $str; }
注意:正则方案无法处理交叉嵌套的括号,栈方案则可以正确处理所有嵌套情况。
内容的提问来源于stack exchange,提问作者electrode
相关产品推荐
相关产品推荐

