按任何顺序匹配子模式

时间:2013-10-27 02:00:11

标签: php regex perl

我有很长的正则表达式,里面有两个复杂的子图。我怎么能以任何顺序匹配那个子模式?

简化示例:

/(apple)?\s?(banana)?\s?(orange)?\s?(kiwi)?/

我希望与

相匹配
apple banana orange kiwi
apple orange banana kiwi

这是一个非常简单的例子。在我的情况下,bananaorange是很复杂的子模式,我不想做像

这样的事情
/(apple)?\s?((banana)?\s?(orange)?|(orange)?\s?(banana)?)\s?(kiwi)?/

是否可以将子模式分组为字符类中的字符?

根据要求提供UPD实际数据:

14:24 26,37 Mb
108.53 01:19:02 06.07
24.39 19:39
46:00

我的琴弦要长得多,但它很重要。在这里你可以看到我需要匹配的两行。 首先有两个值:length(14分24秒)和size 26.37 Mb。 第二个有三个值,但顺序不同:size 108.53 Mb,length 01 h 19 m 02 s和date June,07 第三个有两个sizelength 第四只有length 还有更多变化,我需要解析所有值。

我有一个非常接近的正则表达式,除非我无法弄清楚如何在不写入两次的情况下以不同的顺序匹配模式。

 (?<size>\d{1,3}\[.,]\d{1,2}\s+(?:Mb)?)?\s?
 (?<length>(?:(?:01:)?\d{1,2}:\d{2}))?\s*
 (?<date>\d{2}\.\d{2}))?

注意:这只是大正则表达的一部分,已经好了。

2 个答案:

答案 0 :(得分:2)

或许以下"And" in regular expressions '&&'的改编会有所帮助:

use strict;
use warnings;

while(<DATA>){
    print "Matched: $_" if /^(?=.*\bapple\b)(?=.*\bbanana\b)(?=.*\borange\b)(?=.*\bkiwi\b)/
}

__DATA__
apple banana orange kiwi
apple orange banana kiwi
apple orange banana
kiwiorange bananaapple

输出:

Matched: apple banana orange kiwi
Matched: apple orange banana kiwi

这有效地在正则表达式中创建逻辑 AND ,其中合取的顺序不重要。

答案 1 :(得分:0)

编辑的另一种方式:

我假设一行不能包含多个日期,长度或大小,我使用简单的替换:

$subject = <<<'LOD'
14:24 26,37 Mb
108.53 01:19:02 06.07
24.39 19:39
46:00
LOD;

$pattern = <<<'LOD'
~
^
(?>
    (?> (?<date>   (?> 0[0-9] | 1[012] ) \. (?> [0-2][0-9] | 3[01] )(?! \h+  Mb) ) 
      | (?<length> (?> (?>01:)? [0-9]{1,2} : [0-9]{2} )              )
      | (?<size>   [1-9][0-9]{0,2} [.,] [0-9]?[1-9] (?> \h+  Mb)?    )
    )
    (?> \h | $ )
){1,3} $
~xm
LOD;

preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);

print_r($matches);

\h:水平白色字符(空格或制表符)

条件方式:

您可以使用条件(?(condition)true|false)

(banana)? orange (?(-1)|\g<-1>)

其中-1是捕获组的相对位置(即:最后一个),\g<-1>指的是此捕获组。

您可以通过以下方式翻译此条件模式:如果左侧的第一个捕获组捕获了某些内容,则其他任何内容都不会与捕获组匹配

PHP示例文本示例:

$subject = <<<'LOD'
apple banana orange kiwi
apple orange banana kiwi
LOD;

$pattern = '~(apple)?\s?(banana)?\s?(orange)?\s?(?(-2)|\g<-2>)\s?(kiwi)?~';

preg_match_all($pattern, $subject, $matches);

print_r($matches);


注意:

您可以使用oniguruma语法\g<...>轻松重用子模式:

\g<2>    # second capturing group of the pattern
\g<-2>   # second capturing group on the left from the current position
\g<+2>   # the same on the right
\g<size> # refer to the subpattern of the named capture (?<size>...)

如果需要,可以使用定义部分构建模式,例如:

$pattern = <<<'LOD'
~
# definitions 
(?(DEFINE)
    (?<b> banana )
    (?<o> orange )
    (?<fruit> \g<b> | \g<o> | kiwi | apple )
)

# pattern
\g<b> \s \g<o> | \g<o> \s \g<b>

~x
LOD;

使用这种工具,您可以避免重复子模式的内容。