2

我有很长的正则表达式,里面有两个复杂的子模式。我如何以任何顺序匹配这些子模式?

简化示例:

/(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 秒)和size26.37 Mb。第二个有三个值,但顺序不同:size108.53 Mb, length01 h 19 m 02 s 和dateJune, 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}))?

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

4

2 回答 2

2

也许正则表达式'&&'中对“And”的以下改编会有所帮助:

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

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

于 2013-10-27T02:17:50.523 回答
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>)

where-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;

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

于 2013-10-27T02:14:35.643 回答