一个字符串的PhP正则表达式,最好的方法是什么?

时间:2017-07-07 08:43:45

标签: php regex laravel laravel-5

我有一个rule字段的数组,其字符串如下:

FREQ=MONTHLY;BYDAY=3FR
FREQ=MONTHLY;BYDAY=3SA
FREQ=WEEKLY;UNTIL=20170728T080000Z;BYDAY=MO,TU,WE,TH,FR
FREQ=MONTHLY;UNTIL=20170527T100000Z;BYDAY=4SA
FREQ=WEEKLY;BYDAY=SA
FREQ=WEEKLY;INTERVAL=2;BYDAY=TH
FREQ=WEEKLY;BYDAY=TH
FREQ=WEEKLY;UNTIL=20170610T085959Z;BYDAY=SA
FREQ=MONTHLY;BYDAY=2TH

每一行都是一个不同的数组,我提供了一些线索来了解我的需求。

我需要的是编写一个可以取消所有不必要值的正则表达式。

所以,我不需要FREQ =; BYDAY =等我基本上需要在=之后的值,但每个我想存储在一个不同的变量中。

以第三个为例,它将是:

$frequency = WEEKLY
$until = 20170728T080000Z
$day = MO, TU, WE, TH, FR

它不一定是一个正则表达式,每个值可以有一个正则表达式。所以我有一个FREQ:

preg_match("/[^FREQ=][A-Z]+/", $input_line, $output_array);

但不幸的是,我不能为其他人做这件事,我怎么能解决这个问题?

3 个答案:

答案 0 :(得分:2)

唯一的方法是PHP数组解构:

$str = "FREQ=WEEKLY;UNTIL=20170728T080000Z;BYDAY=MO,TU,WE,TH,FR";

preg_match_all('~(\w+)=([^;]+)~', $str, $matches);
[$freq, $until, $byday] = $matches[2]; // As of PHP 7.1 (otherwise use list() function)
echo $freq, " ", $until, " ", $byday;
// WEEKLY 20170728T080000Z MO,TU,WE,TH,FR

Live demo

更一般

使用extract功能:

preg_match_all('~(\w+)=([^;]+)~', $str, $m);
$m[1] = array_map('strtolower', $m[1]);
$vars = array_combine($m[1], $m[2]);
extract($vars);
echo $freq, " ", $until, " ", $byday;

Live demo

答案 1 :(得分:1)

注意:对于这个问题,我建议使用@revo发布的generell方法,它简洁,安全且容易上手 - 但请记住,与固定字符串函数相比,正则表达式会带来性能损失,所以如果你可以使用strpos / substr / explode / ...,尝试使用它们,不要“膝盖反射”到基于preg_的解决方案。

由于分隔符是固定的,并且似乎没有出现在您感兴趣的值中,并且您还依赖于键的知识(FREQ:等),因此您不需要使用正则表达式(尽可能多我喜欢在任何地方使用它们,你可以在这里使用它们;为什么不简单地在这种情况下爆炸和分裂?

$lines = explode("\n", $text);
foreach($lines as $line) {
    $parts = explode(';', $line);
    $frequency = $until = $day = $interval = null;
    foreach($parts as $part) {
        list($key, $value) = explode('=', $part);
        switch($key) {
             case 'FREQ':
                   $frequency = $value;
                   break;
             case 'INTERVAL':
                   $interval = $value;
                   break;
              // and so on
         }
    }
    doSomethingWithTheValues();
}

如果您的用例非常简单,那么这可能更具可读性和效率。

答案 2 :(得分:0)

您需要使用模式

;?[A-Z]+=

与preg_split();

一起使用
preg_split('/;?[A-Z]+=/', $str);

解释

;       match Semikolon
?       no or one of the last Character
[A-Z]+  match one or more uppercase Letters
=       match one =

如果你想让每一行成为一个单独的数组,你应该这样做:

 # split each Line into an Array-Element
 $lines = preg_split('/[\n\r]+/', $str);

 # initiate Array for Results
 $results = array();

 # start Looping trough Lines
 foreach($lines as $line){

  # split each Line by the Regex mentioned above and
  # put the resulting Array into the Results-Array
  $results[] = preg_split('/;?[A-Z]+=/', $line);

 }