PHP Разбивает строку с разделителями на пары Ключ/Значение (Ассоциативный массив)
У меня есть строка, подобная этой:
key1\value1\key2\value2\key3\value3\key4\value4\key5\value5
И я бы хотел, чтобы это был ассоциативный массив, чтобы я мог сделать:
echo $myArray['key1']; // prints value1
echo $myArray['key3']; // prints value3
//etc...
Я знаю, что могу взорваться на обратной косой черте, но не уверен, как поступить дальше.
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
и сбора массива.
Как насчет чего-то вроде этого:
$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
- один элемент в качестве ключа - тот, на который указывает
Я не очень хорошо разбираюсь в регулярных выражениях, но как насчет этого однострочного кода
parse_str(preg_replace("/key(.*?)\\value(.*?)(\\|$)/", "key$1=value$2&", $input_lines), $output);