用于url字符串的PHP RegExp

时间:2015-05-27 12:38:48

标签: php regex

示例字符串:

accuracy-is-5

accuracy-is-5-or-15

accuracy-is-5-or-15-or-20

package-is-dip-8-or-dip-4-or-dip-16

我当前的正则表达式:

/^([a-z0-9\-]+)\-is\-([a-z0-9\.\-]*[a-z0-9])(?:\-or\-([a-z0-9\.\-]*[a-z0-9]))*$/U

没有固定长度,部分:

\-or\-[a-z0-9\.\-]

可以重复。

Bot现在从字符串“precision-is-5-or-15-or-20”获得:

Array ( [0] => accuracy-is-5-or-15-or-20 [1] => accuracy [2] => 5 [3] => 20 )

15岁在哪里? :) Tnx。

2 个答案:

答案 0 :(得分:5)

^\w+(?:-[a-zA-Z]+)+\K|\G(?!^)-(\d+)(?:(?:-[a-zA-Z]+)+|$)

您可以在此处使用\G来捕获所有组。无论何时重复捕获组,最后一个值都会覆盖之前的。请参阅演示。

https://regex101.com/r/tS1hW2/3

  

\ G在上一场比赛结束时断言位置或第一场比赛的字符串开头

编辑:

^\w+-is(?:-dip)?\K|\G(?!^)-(\d+)(?:-or(?:-dip)?|$)

如果您确定is,or and dip,可以使用此功能。请参阅演示。

https://regex101.com/r/tS1hW2/4

$re = "/^\\w+-is(?:-dip)?\\K|\\G(?!^)-(\\d+)(?:-or(?:-dip)?|$)/m"; 
$str = "accuracy-is-5\naccuracy-is-5-or-15\naccuracy-is-5-or-15-or-20\npackage-is-dip-8-or-dip-4-or-dip-16"; 

preg_match_all($re, $str, $matches);

答案 1 :(得分:3)

当在模式中重复捕获组时,先前的值将被最后一个值覆盖。因此,无法使用preg_match设计您的模式。

可能的解决方法包括使用preg_match_all搜索模式的所有匹配项以及\G锚点,该锚点是上一次匹配后的位置。必须编写模式以一次找到一个值。

\G确保所有匹配都是连续的。为了确保已到达字符串的结尾(换句话说,字符串从开始到结尾都是正确格式化的),一种方便的方法是在结尾处创建一个空的捕获组。因此,如果此捕获组出现在最后一个匹配中,则表示格式正确。

define('PARSE_SENTENCE_PATTERN', '~
(?:                                       # two possible beginings:
    \G(?!\A)                              # - immediatly after a previous match 
  |                                       # OR
    \A                                    # - at the start of the string
    (?<subject> \w+ (?>[-.]\w+)*? ) -is-  #  (in this case the subject is captured)
)
(?<value> \w+ (?>[-.]\w+)*? )  # capture the value
(?: -or- | \z (?<check>) )     # must be followed by "-or-" OR the end of the string \z
                               # (then the empty capture group "check" is created)
~x');

function parseSentence ($sentence) {

    if (preg_match_all(PARSE_SENTENCE_PATTERN, $sentence, $matches, PREG_SET_ORDER) &&
        isset(end($matches)['check']) ) 
        return [ 'subject' => $matches[0]['subject'],
                 'values'  => array_reduce ($matches, function($c, $v) {
                                  $c[] = $v['value']; return $c; }, $c = []) ];

    return false; // wrong format

}

// tests
$test_strings = ['accuracy-is-5', 'accuracy-is-5-or-15', 'accuracy-is-5-or-15-or-20',
                 'package-is-dip-8-or-dip-4-or-dip-16',
                 'bad-format', 'bad-format-is-', 'bad-format-is-5-or-'];

foreach ($test_strings as $test_string) {
    var_dump(parseSentence($test_string));
}