带有命名捕获对的正则表达式问题

时间:2011-03-13 14:42:42

标签: php regex

我有以下价值:

start=2011-03-10T13:00:00Z;end=2011-03-30T13:00:00Z;scheme=W3C-DTF

我使用以下正则表达式去除'开始'和'结束'日期并将它们分配给它们自己的命名捕获对:

#^start=(?P<publishDate>.+);end=(?P<expirationDate>.+);#ix'

可能不是绝对最好的REGEX,但如果“开始”和“结束”值都存在,它就足够好了。

现在,如果“expirationDate”丢失,我需要做的仍然是匹配'publishDate',反之亦然。

如何使用单个表达式执行此操作?我不是正则表达式中最伟大的,我开始徘徊于更高级的东西,所以对此的任何帮助都将非常感激。

谢谢!

更新

感谢钟先生,我已用以下表达式解决了这个问题:

 #^(start=(?P<publishDate>.*?);)?(end=(?P<expirationDate>.*?);)?#xi

一如既往,非常感谢大家的帮助。 :)

3 个答案:

答案 0 :(得分:4)

使用(...)?对于可选部分

^(start=(?P<publishDate>.+);)?(end=(?P<expirationDate>.+));)?

答案 1 :(得分:2)

这两个都将命名缓冲区设置为一个值(而不是null或undefined) 我推荐第一个。

1。以任意顺序查找/两者:
/^(?=.*\bstart=(?P<publishDate>.*?);|(?P<publishDate>))(?=.*\bend=(?P<expirationDate>.*?);|(?P<expirationDate>))/ix

/^(?=                                 # from beginning, look ahead for start
       .*\b                               # any character 0 or more times (backtrack to match 'start')
       start=(?P<publishDate>.*?);        # put start date in publish 
    |  (?P<publishDate>)                # OR, put empty string publish 
  )
  (?=                                 # from beginning, look ahead for end
       .*\b                               # same criteria as above ...
       end=(?P<expirationDate>.*?);
    |  (?P<expirationDate>)
  )
/ix

2. 要按开始/结束顺序查找/两者:
/^(?:.*\bstart=(?P<publishDate>.*?);|(?P<publishDate>))(?:.*\bend=(?P<expirationDate>.*?);|(?P<expirationDate>))/ix

修改

@Josh Davis - 我不得不去寻找PCRE.org,那里有一些很棒的东西。

使用Perl,重复名称没有问题 文档:“如果多个组具有相同的名称,则它指的是当前匹配中最左侧定义的组。” 在交替使用时,这绝不是问题。

使用PCRE ..
如果重复的名称与分支重置一起使用,则它将与PHP一起正常工作 分支重置可确保重复的名称将占用相同的捕获组 之后,使用dup名称常量,$ match ['name']将包含值
或空字符串,但它会存在。

即:

(?J)= PCRE_DUPNAMES
(?| ... | ...)=分支重置

这有效:
/(?Ji)^
(?= (?| .* end = (?P<expirationDate> .*? ); | (?P<expirationDate>)) )
(?= (?| .* start = (?P<publishDate> .*? ); | (?P<publishDate>)) )
/x

在此处试试:http://www.ideone.com/zYd24

<?php 
$string = "start=2011-03-(start)10T13:00:00Z;end=2011-03-(end)30T13:00:00Z;scheme=W3C-DTF"; 
preg_match('/(?Ji)^
      (?= (?| .* end = (?P<expirationDate> .*? ); | (?P<expirationDate>)) )
      (?= (?| .* start = (?P<publishDate> .*? ); | (?P<publishDate>)) )
    /x', $string, $matches);
echo "Published = ",$matches['publishDate'],"\n";
echo "Expires   = ",$matches['expirationDate'],"\n"; 
print_r($matches);
?> 

输出

Published = 2011-03-(start)10T13:00:00Z
Expires   = 2011-03-(end)30T13:00:00Z
Array
(
    [0] => 
    [expirationDate] => 2011-03-(end)30T13:00:00Z
    [1] => 2011-03-(end)30T13:00:00Z
    [publishDate] => 2011-03-(start)10T13:00:00Z
    [2] => 2011-03-(start)10T13:00:00Z
)

答案 2 :(得分:0)

如果'start =;'在没有相应日期时不存在,那么Stephen Chung的代码就可以了

否则我认为用'*'代替'+'就足够了:

#^start=(?P<publishDate>.*?);end=(?P<expirationDate>.*?);#ix'

顺便说一句,'?'是必要的,以便在每个代码中都不明白