2015-10-22 2 views
1

У меня есть строка, как показано ниже.Извлечь части строки (PHP)

$str = "ENGINE=InnoDB 
     DEFAULT CHARSET=utf8 
     COLLATE=utf8_unicode_ci 
     COMMENT='Table comment'"; 

И мне нужно, чтобы разобрать пары ключ/значение из строки и объединить их с парами ключ/значение в массиве ниже ...

$arr = array("ENGINE" => "InnoDB", 
      "DEFAULT CHARSET" => "utf8", 
      "COLLATE" => "utf8_unicode_ci", 
      "COMMENT" => "'Table comment'"); 

Здесь последовательность частей строка может быть разной.

Пример:

$str = "ENGINE=InnoDB 
     COMMENT='Table comment' 
     COLLATE=utf8_unicode_ci 
     DEFAULT CHARSET=utf8"; 
+1

Что вы на самом деле спрашиваете? Вы можете использовать explode(), чтобы превратить строку в массив. – Coz

+3

Как вы решили сломаться между InnoDB и DEFAULT, но не между DEFAULT и CHARSET? –

+1

Вы можете попробовать preg_replace с этим регулярным выражением: https://regex101.com/r/hQ5tD5/1 – Tanner

ответ

6

Вы должны использовать preg_match_all() и есть PHP построить свой выход оттуда в формате, который вы хотели бы. Вот рабочий пример в PHP. И regex statement.

<?php 
    $str = "ENGINE=InnoDB COMMENT='Table comment' COLLATE=utf8_unicode_ci DEFAULT CHARSET=utf8"; 
    preg_match_all("/([\w ]+)=(\w+|'(?:[^'\\\]|\\.)+')\s*/",$str,$matches,PREG_SET_ORDER); 
    $out = []; 
    foreach($matches as $match) { 
     $out[$match[1]] = $match[2]; 
    } 
    var_dump($out); 
?> 

И результат:

array(4) { 
    ["ENGINE"]=> 
    string(6) "InnoDB" 
    ["COMMENT"]=> 
    string(15) "'Table comment'" 
    ["COLLATE"]=> 
    string(15) "utf8_unicode_ci" 
    ["DEFAULT CHARSET"]=> 
    string(4) "utf8" 
} 

Объяснение регулярное выражение

([\w ]+) // match one or more word characters (alpha+underscore+space) 
= // match equals sign 
    (
     \w+ // match any word character 
    | // or 
     ' // match one exact quote character 
     (?:[^'\\]|\\.)+ // match any character including escaped quotes 
     ' // match one exact quote character 
    ) 
\s* // match any amount of whitespace until next match 
+0

Очень круто! Не могли бы вы добавить объяснение регулярного выражения? – zedfoxus

+0

Это то, что я точно ищу. Большое спасибо!! – asankasri

+2

@zedfoxus добавил объяснение для вас –

1

Строка выглядит ini -файла. С parse_ini_string:

$str = "ENGINE=InnoDB DEFAULT 
     CHARSET=utf8 
     COLLATE=utf8_unicode_ci 
     COMMENT='Table comment'"; 

$data = parse_ini_string($str); 
var_dump($data); 

array(4) { 
    ["ENGINE"]=> 
    string(14) "InnoDB DEFAULT" 
    ["CHARSET"]=> 
    string(4) "utf8" 
    ["COLLATE"]=> 
    string(15) "utf8_unicode_ci" 
    ["COMMENT"]=> 
    string(13) "Table comment" 
} 
+0

Он не работает с разделенными пробелами ключами, такими как 'DEFAULT CHARSET' –

+0

@ Давид Боскович, вы это пробовали, этот случай« разделенные пробелами ключи, такие как DEFAULT CHARSET »?) Конечно, он работает. – voodoo417

+0

Ах, неважно, это проблема с вашим примером, а не с самим кодом. Я не думаю, что у айзера есть возможность добавить новые строки, поскольку строка кажется непосредственно из SQL. Но мне нравится подход в теории! Я полностью забыл, что метод существует в PHP. –

0

Вот многословным, безвкусный способ разбора данных (с большим количеством комментариев-объяснения). Это может быть адаптировано для другой структурированной строки.

<?php 

$str = "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='Table comment'"; 
$keys = array('ENGINE', 'DEFAULT CHARSET', 'COLLATE', 'COMMENT'); 

$str_array = explode('=', $str); 
/* result of the above will be 
[0] => ENGINE 
[1] => InnoDB DEFAULT CHARSET 
[2] => utf8 COLLATE 
[3] => utf8_unicode_ci COMMENT 
[4] => 'Table comment' 
*/ 

$output = array(); 
$lastkey = ''; 

// loop through each split item 
foreach ($str_array as $item) { 

    // if the item is entirely one of the keys, just remember it as the last key 
    if (in_array($item, $keys)) { 
     $lastkey = $item; 
     continue; 
    } 

    // check if item like InnoDB DEFAULT CHARSET contains one of the keys 
    // if item contains a key, the key will be returned 
    // Otherwise, item will be returned 
    $result = item_has_a_key($item, $keys); 

    if ($result === $item) { 
     // if the result is exactly the item, that means no key was found in the item 
     // that means, it is the value of the previously found key 
     $output[$lastkey] = $item; 
    } else {  
     // if the result is not exactly the item, that means it contained one of the keys 
     // strip out the key leaving only the value. Assign the value to previously found key 
     $output[$lastkey] = trim(str_replace($result, '', $item)); 

     // remember the key that was found 
     $lastkey = $result; 
    } 
} 

print_r($output); 
/* 
Result: 
[ENGINE] => InnoDB 
[DEFAULT CHARSET] => utf8 
[COLLATE] => utf8_unicode_ci 
[COMMENT] => 'Table comment' 
*/ 


// $item can be InnoDB DEFAULT CHARSET 
// $keys is the array of keys you have assigned (ENGINE, DEFAULT CHARSET etc.) 
// if the item contains one of the keys, the key will be returned 
// if the item contains no key, the item will be returned 
function item_has_a_key($item, $keys) { 
    foreach ($keys as $key) { 
     if (strpos($item, $key) !== false) { 
      return $key; 
     } 
    } 
    return $item; 
} 
?> 
+0

* blinks * Похоже, вы пытаетесь пойти в сторону хакерского лексера. Письмо Lexer - довольно законный материал. Посмотрите эту статью, если вы собираетесь провести вечернюю забаву: http://nitschinger.at/Writing-a-simple-lexer-in-PHP –

+0

Спасибо, что поделились, @DavidBoskovic! – zedfoxus

Смежные вопросы