如何更正 preg_match_all 正则表达式中子模式的结果?

How to correct result from subpatterns in regular expression of preg_match_all?

我有这个代码:

$query = 'CREATE table "msg" ( "myid" INT(10) UNSIGNED , "user" INT(10) UNSIGNED , "new_mes" SMALLINT(5) UNSIGNED , "total_mes" MEDIUMINT(8) UNSIGNED , "lastdate" DATETIME , PRIMARY KEY ("ids"), KEY ("lastdate") )'; 

我正在尝试使用此子模式获取主键和密钥:

preg_match_all('/(?:\WPRIMARY\W*KEY\W?\()(?P<PRIMARY_KEY>[^)]+)|'.
        '(?:\W*KEY\W?\()(?P<KEY>[^)]+)/i',$query,$results);
        $primary_key = isset($results['PRIMARY_KEY'][0]) ? $results['PRIMARY_KEY'][0] : '';
        $key = isset($results['KEY'][0]) ? $results['KEY'][0] : '';
    print_r($results);

我得到这个输出:

Array
(
    [0] => Array
        (
            [0] =>  PRIMARY KEY ("ids"
            [1] => ),KEY ("lastdate"
        )

    [PRIMARY_KEY] => Array
        (
            [0] => "ids"
            [1] => 
        )

    [1] => Array
        (
            [0] => "ids"
            [1] => 
        )

    [KEY] => Array
        (
            [0] => 
            [1] => "lastdate"
        )

    [2] => Array
        (
            [0] => 
            [1] => "lastdate"
        )
)

我查找了用双引号括起来的词。结果几乎是 find 但我更愿意在第一个索引 [0] 中获取 "ids" 和 "lastdate" 这两个词。你能解释一下为什么第一个词放在第一个索引中,而第二个词放在第二个索引中吗?以及为什么第二个和第一个索引中有空字符串。

有没有办法让索引 0 上的两个词都出现?只是为了简化代码。

您可以在右上角的边栏中查看您的正则表达式如何与 Regex101 一起使用。

完成这项工作的另一种方法 (see online demo):

<?php
// I added a primary key `myid` to demonstrate a capture with several keywords
$query = 'CREATE table "msg" ( "myid" INT(10) UNSIGNED , "user" INT(10) UNSIGNED , "new_mes" SMALLINT(5) UNSIGNED , "total_mes" MEDIUMINT(8) UNSIGNED , "lastdate" DATETIME , PRIMARY KEY ("ids", "myid"), KEY ("lastdate") )'; 

// 1. Note the \b anchor to ensure that the capture begins at the start of a word
// 2. PREG_SET_ORDER to keep structure simplier
preg_match_all('#\b((?:PRIMARY\s*?)?KEY) \(([^\)]*)\)#i', $query, $results, PREG_SET_ORDER);

$primary_keys = [];
$keys = [];

foreach ($results as $result) {
    $values = explode(',', $result[2]); // get separate words
    array_walk($values, function (&$v) { $v = trim($v, ' "'); }); // remove quotes and spaces
    if (0 === stripos($result[1], 'PRIMARY')) {
        $primary_keys = array_merge($primary_keys, $values);
    }
    else {
        $keys = array_merge($keys, $values);
    }
}

echo "Found primary keys:\n";
print_r($primary_keys);
echo "Found keys:\n";
print_r($keys);

echo "\n$results:\n";
print_r($results);

结果:

Found primary keys:
Array
(
    [0] => ids
    [1] => myid
)
Found keys:
Array
(
    [0] => lastdate
)

$results:
Array
(
    [0] => Array
        (
            [0] => PRIMARY KEY ("ids", "myid")
            [1] => PRIMARY KEY
            [2] => "ids", "myid"
        )

    [1] => Array
        (
            [0] => KEY ("lastdate")
            [1] => KEY
            [2] => "lastdate"
        )

)

您可以在 Regex101 上看到 this new version is more efficient that the old one 捕获结果需要 377 步和 904 步。