返回多个匹配项,但仅在使用PHP和RegEX首次出现模式之前

时间:2019-06-16 16:26:53

标签: php regex

我的数据集看起来像

I(0,123...789){
A(0,567...999){.......n=Marc.....}
B(2,655...265){..................}
C(3,993...333){..................}
M(8,635...254){.................;}
}
O(0,345...789){
A(0,567...999){.......n=Marc.....}
B(2,876...775){..................}
C(3,993...549){..................}
M(8,354...987){.................;}
}
I(0,987...764){
A(0,567...999){.......n=Marc.....}
B(2,543...265){..................}
C(7,998...933){..................}
M(8,645...284){.................;}
}
B(0,123...789){
.......
}
I(0,987...764){
A(0,567...999){.......n=John.....}
B(2,543...265){..................}
C(7,998...933){..................}
M(8,645...284){.................;}
}

我试图返回所有的I“节”,所以从“ I”开始直到;}之后的结束标记,但前提是“ I”节包含n = Marc。

到目前为止,我来了

^([I]\(.*\){.*n=Marc.*^[M]\(.*;}.)}

https://regex101.com/r/VSuZh5/1

但是在某些情况下,当数据具有类似模式

I(0,123...789){
A(0,567...999){.......n=Marc.....}
B(2,655...265){..................}
C(3,993...333){..................}
M(8,635...254){.................;}
}
O(0,345...789){
A(0,567...999){.......n=Marc.....}
B(2,876...775){..................}
C(3,993...549){..................}
M(8,354...987){.................;}
}

正则表达式返回I和O部分。有没有办法确保它总是返回I部分?

  • 对数据集表示歉意,它很庞大,并且包含许多我无法公开的敏感数据。*

3 个答案:

答案 0 :(得分:2)

一种选择可能是匹配I,然后匹配所有不以}开头的行,并且至少匹配包含n=Marc的一行

^I\([^()]*\){(?:\R(?!}|.*n=Marc).*)*\R.*\bn=Marc\b.*(?:\R(?!}).*)*\R}$

说明

  • ^字符串的开头
  • I\([^()]*\){匹配I后跟(...){
  • (?:非捕获组
    • \R(?!}|.*n=Marc)匹配unicode换行符序列,断言右边不是}或该行包含n = Marc
    • .*匹配任何char 0次以上
  • )*关闭非捕获组并重复0次以上
  • \R匹配unicode换行符序列
  • .*\bn=Marc\b.*匹配任何char 0+次并匹配单词边界之间的n=Marc
  • (?:非捕获组
    • \R(?!}).*匹配换行序列,断言右边不是}
  • )*关闭非捕获组并重复0次以上
  • \R匹配换行符序列
  • }比赛结束}
  • $字符串结尾

Regex demo

答案 1 :(得分:2)

如果我知道的话,输入总是像样本一样格式化,宁愿在行首的}结束处分成多个块,如果后面有一个上一行:^}\R(?=[A-Z]),则换行。

然后使用preg_grep查找以I开头并包含n=Marc的项目。

$res = preg_grep('/^I.*n=Marc/s', preg_split('/^}\R(?=[A-Z])/m', $str));

See PHP demo at 3v4l.org

在您的模式中,.*可以跳过不需要的项目,从而导致意外的匹配。

答案 2 :(得分:0)

我的猜测是,我们希望表达式返回包含O的{​​{1}}部分,类似于:

n=Marc

或者:

(?=O\()([\s\S]*?n=Marc[\s\S]*?;}\s*})

Demo 1

对于(?=O\()([\s\S]*?n=Marc[\s\S]*?;})\s*} 部分,我们只需将I更改为O

I

Demo 2

测试

(?=I\()([\s\S]*?n=Marc[\s\S]*?;})\s*}

输出

$re = '/(?=I\()([\s\S]*?n=Marc[\s\S]*?;})\s*}/m';
$str = 'I(0,123...789){
A(0,567...999){.......n=Marc.....}
B(2,655...265){..................}
C(3,993...333){..................}
M(8,635...254){.................;}
}
O(0,345...789){
A(0,567...999){.......n=Marc.....}
B(2,876...775){..................}
C(3,993...549){..................}
M(8,354...987){.................;}
}
I(0,987...764){
A(0,567...999){.......n=Marc.....}
B(2,543...265){..................}
C(7,998...933){..................}
M(8,645...284){.................;}
}
B(0,123...789){
.......
}
I(0,987...764){
A(0,567...999){.......n=John.....}
B(2,543...265){..................}
C(7,998...933){..................}
M(8,645...284){.................;}
}';

preg_match_all($re, $str, $matches, PREG_SET_ORDER, 0);

foreach ($matches as $key => $I) {
    echo $I[0] . "\n";
}