如何编写兼容PHP和JS的正则捕获OS组名及组内内容?
问题
我有如下格式的数据文件:
[linux] foo faafaa fii [windows] faa fii@@ <tag1>fuu</tag1> foo1234 [osname3] faa faa [osname4] fiifoo
需要捕获所有OS名称及其对应的组内内容,其中OS的数量和组内容都是可变的,组内容可包含任意字符。预期匹配结果如下:
Match1 : Groupe1 : 'linux' Groupe2 : 'foo faafaa' Match2 : Groupe1 : 'windows' Groupe2 : ' faa fii@@ <tag1>fuu</tag1> foo1234 ' Match3 : Groupe1 : 'osname3' Groupe2 : 'faa faa' Match4 : Groupe1 : 'osname4' Groupe2 : 'fiifoo'
我尝试的正则表达式为:(?:\[([\S ]+)\]\n((?:[\s\S\n])(?!\n\[))*),但匹配结果不符合预期,问题出在(?:[\s\S\n])(?!\n\[))*部分。我希望捕获所有字符,但在\n\[模式前停止匹配,却无法实现。此外,该正则需要同时兼容PHP和JavaScript,恳请提供解决帮助。
解决方案
修正后的正则表达式
\[([^\]]+)\]([\s\S]*?)(?=\n\[|\Z)
正则说明
\[([^\]]+)\]:匹配OS名称的方括号部分,捕获组1提取OS名称——用[^\]]+匹配除右括号外的所有字符,避免误匹配其他方括号内容([\s\S]*?):非贪婪模式匹配任意字符(含换行),捕获组2提取对应OS的内容,*?是核心,能防止过度匹配到下一个OS的起始部分(?=\n\[|\Z):正向预查,当匹配到\n\[(下一个OS的起始行)或者文本末尾\Z时停止,刚好满足“在新行左括号前停止匹配”的需求
兼容PHP和JavaScript的使用示例
JavaScript 示例
const data = `[linux] foo faafaa fii [windows] faa fii@@ <tag1>fuu</tag1> foo1234 [osname3] faa faa [osname4] fiifoo`; const regex = /\[([^\]]+)\]([\s\S]*?)(?=\n\[|\Z)/g; let match; while ((match = regex.exec(data)) !== null) { console.log(`Match${regex.lastIndex / match[0].length} : Groupe1 : '${match[1]}' Groupe2 : '${match[2]}'`); }
PHP 示例
$data = <<<EOD [linux] foo faafaa fii [windows] faa fii@@ <tag1>fuu</tag1> foo1234 [osname3] faa faa [osname4] fiifoo EOD; $regex = '/\[([^\]]+)\]([\s\S]*?)(?=\n\[|\Z)/'; preg_match_all($regex, $data, $matches, PREG_SET_ORDER); foreach ($matches as $index => $match) { echo "Match".($index+1)." : Groupe1 : '{$match[1]}' Groupe2 : '{$match[2]}'\n\n"; }
原正则失效原因
原正则里的(?:[\s\S\n])(?!\n\[))*逻辑有问题:[\s\S]已经包含了换行符,不需要额外加\n;而且这个断言是对单个字符做检查,无法识别\n\[这个双字符的结束标记,导致匹配要么吃掉换行符停在[前,要么过度匹配。用正向预查(?=\n\[|\Z)可以准确识别结束边界,配合非贪婪匹配*?就能精准捕获每个OS的内容。
内容的提问来源于stack exchange,提问作者spacecodeur
相关产品推荐
相关产品推荐

