Я пытаюсь проанализировать строку со следующей структурой в PHP:
a,b,c(d,e,f(g),h,i(j,k)),l,m,n(o),p
Например, «настоящая» строка будет:
id,topic,member(name,email,group(id,name)),message(id,title,body)
Мой конечный результат должен быть массивом:
[ id => null, topic => null member => [ name => null, email => null, group => [ id => null, name => null ] ], message => [ id => null, title => null, body => null ] ]
Я пробовал рекурсивное регулярное выражение, но полностью потерял его. У меня есть некоторый успех при повторении строковых символов, но это кажется немного «сложным», и я уверен, что это то, что может обрабатывать регулярное выражение, я просто не знаю, как это сделать.
Цель состоит в том, чтобы проанализировать параметр запроса полей для REST API, чтобы позволить клиенту выбирать поля, которые он хочет, из коллекции сложных объектов, и я не хочу ограничивать «глубину» выбора поля.
Как отметил Wiktor, это можно сделать с помощью лексера. Следующий ответ использует класс, первоначально из Никиты Попопва, который можно найти здесь .
Он просматривает строку и ищет совпадения, как определено в $tokenMap
. Они определяются как T_FIELD
, T_SEPARATOR
, T_OPEN
и T_CLOSE
. Найденные значения помещаются в массив с именем $structure
.
Впоследствии нам нужно перебрать этот массив и построить из него структуру. Поскольку могут быть множественные вложения, я выбрал рекурсивный подход ( generate()
).
Демо можно найти на ideone.com .
Фактический код с пояснениями:
// this is our $tokenMap $tokenMap = array( '[^,()]+' => T_FIELD, # not comma or parentheses ',' => T_SEPARATOR, # a comma '\(' => T_OPEN, # an opening parenthesis '\)' => T_CLOSE # a closing parenthesis ); // this is your string $string = "id,topic,member(name,email,group(id,name)),message(id,title,body)"; // a recursive function to actually build the structure function generate($arr=array(), $idx=0) { $output = array(); $current = null; for($i=$idx;$i<count($arr);$i++) { list($element, $type) = $arr[$i]; if ($type == T_OPEN) $output[$current] = generate($arr, $i+1); elseif ($type == T_CLOSE) return $output; elseif ($type == T_FIELD) { $output[$element] = null; $current = $element; } } return $output; } $lex = new Lexer($tokenMap); $structure = $lex->lex($string); print_r(generate($structure));