Извлечь части строки (PHP)

1

У меня есть строка, как показано ниже.

$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 (), чтобы превратить строку в массив.
  • 3
    Как вы определяете разрыв между InnoDB и DEFAULT, но не между DEFAULT и CHARSET?
Показать ещё 2 комментария
Теги:
string

3 ответа

6
Лучший ответ

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

<?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
    Очень круто! Не могли бы вы добавить объяснение регулярного выражения?
  • 0
    Именно это я и ищу. Большое спасибо!!
Показать ещё 2 комментария
1

Строка выглядит как ini -file. С помощью 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 ключами, такими как DEFAULT CHARSET
  • 0
    @ Дэвид Бошкович, вы пробовали это, в этом случае space seperated keys like DEFAULT CHARSET ?) Конечно, это работает.
Показать ещё 1 комментарий
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
    мигает Похоже, вы пытаетесь пойти в направлении хакерского лексера. Написание лексера - довольно законный материал. Прочтите эту статью, если вы хотите развлечься поздно ночью: nitschinger.at/Writing-a-simple-lexer-in-PHP
  • 0
    Спасибо, что поделились, @DavidBoskovic!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню