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


У меня есть строка, подобная этой:

key1\value1\key2\value2\key3\value3\key4\value4\key5\value5

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

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

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

Author: Rizier123, 2011-03-13

3 answers

Используя простое регулярное выражение через preg_match_all и array_combine часто это самый короткий и быстрый вариант:

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

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

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

Отчетливый 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+, чтобы регулярное выражение пропускало нежелательные события:

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

Это самый тривиальный подход к внесению в белый список. Если вы хотите утверждать/заранее ограничить всю строку ключа/значения, затем создайте отдельный 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 и сбора массива.

 17
Author: mario, 2017-05-23 12:09:41

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

$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
 6
Author: Pascal MARTIN, 2011-03-13 15:36:42

Я не очень хорошо разбираюсь в регулярных выражениях, но как насчет этого однострочного кода

parse_str(preg_replace("/key(.*?)\\value(.*?)(\\|$)/", "key$1=value$2&", $input_lines), $output);
 0
Author: Wasim A., 2016-12-03 19:57:07