2014-07-04 149 views
2

我一直在想,如果有可能只是单独使用正则表达式来解决以下问题:正则表达式只捕捉组

我有文本的多行字符串,其中有关通过Z!,另一端S0634分离,像这样的信息:

Z! EXT .000 ...HOUSE... L24JN7 
PERSONAL COMPUTER\J\039060-L24JN7-000-*****-*****- 
Payroll No.: 1 
-Name: 
-Folios: 
-Date: 6/24/2014 
-Subformat: S0634 
Z! EXT .000 ...HOUSE... L24JN7 
PERSONAL COMPUTER\J\039060-L24JN7-000-*****-*****- 
Payroll No.: 2 
-Name: 
-Date: 6/24/2014 
-Subformat: S0634 
Z! EXT .000 ...HOUSE... L24JN7 
PERSONAL COMPUTER\J\039060-L24JN7-000-*****-*****- 
Payroll No.: 3 
-Name: 
-Folios: 
-Date: 6/24/2014 
-Subformat: S0634 
desired content.</li> 

我试图捕捉仅通过上述边界组提到的两个字符序列,并包含词Folios。如果你仔细观察,中间的一组没有它。所以,我需要返回的数组只有2个包含该关键字的组。 我可以将它分成组,我也可以返回没有它的组,e.q. (Z!\s*EXT(?:(?!-Folios:).)*?S0634)。然而,捕捉那些拥有它的群体却无法回避。
我只对正则表达式单行代码解决方案感兴趣。我知道我可以将它拆分成组,然后检查每个组。 任何帮助表示赞赏!

回答

4

使用此:

$regex = '~(?sm)Z!(?:(?!S0634).)*?Folios.*?S0634~'; 
preg_match_all($regex, $yourstring, $matches); 
// See all matches 
print_r($matches[0]); 

the demo,你可以看到,中年组被排除在外。

输出:

Array 
(
    [0] => Z! EXT .000 ...HOUSE... L24JN7 
PERSONAL COMPUTER\J9060-L24JN7-000-*****-*****- 
Payroll No.: 1 
-Name: 
-Folios: 
-Date: 6/24/2014 
-Subformat: S0634 

    [1] => Z! EXT .000 ...HOUSE... L24JN7 
PERSONAL COMPUTER\J9060-L24JN7-000-*****-*****- 
Payroll No.: 3 
-Name: 
-Folios: 
-Date: 6/24/2014 
-Subformat: S0634 
) 

说明

  • (?s)激活DOTALL模式,允许点到跨线
  • (?m)接通多行模式匹配,从而允许^$到比赛在每一行
  • Z!匹配起始定界符
  • (?:(?!S0634).)*?懒洋洋地匹配后不跟S0634,到任何字符...
  • Folios
  • .*?S0634懒洋洋字符串的其他部分相匹配到结束分隔符

参考

2

你可以用这种模式做到这一点:

Z!(?>(?!Z!).*\R)+?\s*-Folios:(?>(?!Z!).*\R)*?.* S0634 

(?!Z!)避免匹配有Folios下一个组。这确保FoliosS0634处于同一组中。

+0

+1替代解决方案,你总是非常善于使用原子组! :) – zx81

+0

@KEHT你可以像这样重复Caz'z“line skipper”:'Z!(?>(?! Z!)。* \ R)+?\ s * Payroll No .: 3(?>(?使用一个子程序。或者使用一个子程序。(例如:!Z!)。* \ R)+?\ s * -Folios:(?>(?! Z!)。* \ R)*?。* S0634' – zx81