2016-05-14 32 views
1

我有這樣的代碼:如何更正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"))'; 

我試圖讓主鍵和鍵使用此subpaterns:

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" 
     ) 
) 

我找的用雙引號括起來的單詞。結果幾乎可以找到,但我更願意在第一個索引[0]中獲取兩個單詞「ids」和「lastdate」。你能解釋爲什麼它發生在第一個索引中的第一個詞被放置,而第二個索引被放置在第二個索引中?爲什麼在第二和第一個索引中有空字符串。

有沒有辦法如何讓兩個詞在索引0?只是爲了簡化代碼。

+0

你是否需要所有的命名捕獲組?您可以使用['(?| \ WPRIMARY \ W * KEY \ W?\(([^)] +)| \ W * KEY \ W?\(([^)] +))'](https: //regex101.com/r/kG6nE6/1)。請參閱[本演示](http://ideone.com/sBLOYZ)。 –

+0

我知道我不需要他們。我創造它們只是爲了說清楚。 –

回答

2

你可以檢查你的正則表達式如何與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是更高效,the old one 377個步驟VS 904獲取結果的步驟。

+0

謝謝。這一個更好。你的模式中的\ b是什麼? –

+1

@JohnBoe它表明我搜索找到單詞'PRIMARY'或'KEY'的開頭。正則表達式引擎可以通過簡單地測試要解析的文本詞語的開頭來優化研究。 此外,我確保包含'PRIMARY'或'KEY'的另一個單詞不會被捕獲,就像'FOREIGN KEY'。 – piouPiouM