PHP разделил строку с разделителями на пары ключ / значение (ассоциативный массив)

у меня есть такая строка:

key1value1key2value2key3value3key4value4key5value5

и я хотел бы, чтобы это был ассоциативный массив, чтобы я мог сделать:

echo $myArray['key1']; // prints value1
echo $myArray['key3']; // prints value3
//etc...

Я знаю, что могу взорваться на обратной косой черте, но не уверен, как идти оттуда.

3 ответов


использовать простой regex via preg_match_all и array_combine часто самый короткий и самый быстрый вариант:

 preg_match_all("/([^\\]+)\\([^\\]+)/", $string, $p);
 $array = array_combine($p[1], $p[2]);

теперь это, конечно, особый случай. Оба!--46-->ключи и значения разделены\ обратная косая черта, как и все пары из них. Регулярное выражение также немного длиннее из-за необходимого двойного экранирования.

однако эта схема может быть обобщена на другие key:value,строк в стиле.

Distinct key:value, разделители

общие варианты включают : и = как разделители ключа / значения, и , или & и другие в качестве разделителей пар. Регулярное выражение становится довольно очевидным в таких случаях (с /x флаг для удобства чтения):

 #                    ↓    ↓    ↓
 preg_match_all("/ ([^:]+) : ([^,]+) /x", $string, $p);
 $array = array_combine($p[1], $p[2]);

что делает его очень легко обмениваться : и , для других разделителей.

  • знаки равенства = вместо : двоеточие.
  • \t как разделитель пар (разделенный вкладками ключ: списки значений)
  • классический & или ; как разделитель между парами ключ=значение.
  • или просто \s пробелы или \n даже новые линии.

разрешить различные разделители

вы можете сделать его более гибким / прощающим, разрешив различные разделители между ключи/значения/пары:

 #                    ↓      ↓       ↓
 preg_match_all("/ ([^:=]+) [:=]+ ([^,+&]+) /x", $string, $p);

когда как key=value,key2:value2++key3==value3 будет работать. Что может иметь смысл для более дружественных людей (он же нетехнические пользователи).

ограничить буквенно-цифровые клавиши

часто вы можете запретить что-либо, кроме классического key идентификаторы. Просто используйте \w+ word string pattern, чтобы регулярное выражение пропускало нежелательные события:

 #                   ↓   ↓    ↓
 preg_match_all("/ (\w+) = ([^,]+) /x", $string, $p);

это самый тривиальный подход к белому списку. Если OTOH вы хотите утверждаю / предварительно ограничьте всю строку ключа / значения, затем создайте отдельную preg_match("/^(\w+=[^,]+(,|$))+/", …

пробелы полосы или цитирование

вы можете пропустить несколько шагов после обработки (например,trim на ключах и значениях) с небольшим добавлением:

 preg_match_all("/ \s*([^=]+) \s*=\s* ([^,]+) (?<!\s) /x", $string, $p);

или, например, дополнительные цитаты:

 preg_match_all("/ \s*([^=]+) \s*=\s* '? ([^,]+) (?<![\s']) /x", $string, $p);

извлечение в стиле INI

и вы можете создать базовое извлечение INI-файла метод:

 preg_match_all("/^ \s*(\w+) \s*=\s* ['\"]?(.+?)['\"]? \s* $/xm", $string, $p);

обратите внимание, что это просто сырой подмножество общих схем INI.

альтернатива: parse_str()

если у вас key=value&key2=value2 строка уже есть, то parse_str работает как шарм. Но, объединив его с strtr может даже обрабатывать различные другие разделители:

 #                         ↓↓    ↑↑
 parse_str(strtr($string, ":,", "=&"), $pairs);

, который имеет пару плюсы и минусы его собственный:

  • даже короче, чем двухстрочное регулярное выражение.
  • предопределяет известный механизм побега, такой как %2F для специальных символов).
  • не разрешает различные разделители, или неэкранированные разделителей внутри.
  • автоматически заменяет keys[]= массивам, которые вы можете или не хотите.

альтернатива: explode + foreach

вы найдете много примеров расширение строки ручного ключа / значения. Хотя это чаще всего код. explode несколько используется в PHP из-за оптимизационных предположений. После профилирования часто оказывается медленнее, однако из-за руководства foreach и коллекция массив.


как насчет чего-то вроде этого :

$str = 'key1\value1\key2\value2\key3\value3\key4\value4\key5\value5';
$list = explode('\', $str);

$result = array();
for ($i=0 ; $i<count($list) ; $i+=2) {
    $result[ $list[$i] ] = $list[$i+1];
}

var_dump($result);

что бы вы :

array
  'key1' => string 'value1' (length=6)
  'key2' => string 'value2' (length=6)
  'key3' => string 'value3' (length=6)
  'key4' => string 'value4' (length=6)
  'key5' => string 'value5' (length=6)


В принципе, здесь идея заключается в том, чтобы:

  • разделить строку
  • , который даст вам массив, такие как 'key1', 'value1', 'key2', 'value2', ...
  • и затем повторите этот список, с прыжком 2, используя каждый раз :
    • один элемент в качестве ключа -- тот, на который указывает $i
    • только после того, как качество один, на который указывает $i+1

Я не так хорош с RegExp, но как насчет этого кода одной строки

parse_str(preg_replace("/key(.*?)\value(.*?)(\|$)/", "key=value&", $input_lines), $output);