Я пишу программу на PHP (так как она будет сопровождать веб-код для системы оценки математики), и мне нужно создать массив строк и массивов. В частности, я хочу преобразовать что-то вроде
((4)+((5)*(pi)))-((9)*(sqrt(3)))
в
[["4", ["5", "pi", "*"], "+"], ["9", ["3", "sqrt"], "*"], "-"]
который является форматированием массива обратной польской записи. При этом я оценил бы коммутативность среди операторов, чтобы сравнить правильный, сохраненный ответ с ответом студента. Однако я не могу сделать это в PHP с многомерными массивами из-за неровностей строк.
Если есть способ сделать это с помощью строк, это было бы еще более полезно (так как я планирую хранить результаты в базе данных SQL), но для этого я мог бы, вероятно, использовать serialize()
,
Спасибо за любую помощь.
РЕДАКТИРОВАТЬЯ думаю, что получил его на работу. Использование краткой записи в массиве, казалось, вызывало проблему. Старый array()
нотация, кажется, работает правильно, например, так:
array(array("4", array("5", "pi", "*"), "+"), array("9", array("3", "sqrt"), "*"), "-")
и сериализованная запись (для хранения в базе данных):
a:3:{i:0;a:3:{i:0;s:1:"4";i:1;a:3:{i:0;s:1:"5";i:1;s:2:"pi";i:2;s:1:"*";}i:2;s:1:"+";}i:1;a:3:{i:0;s:1:"9";i:1;a:2:{i:0;s:1:"3";i:1;s:4:"sqrt";}i:2;s:1:"*";}i:2;s:1:"-";}.
Вот функция, которая сделает преобразование из строки во вложенный массив:
function convert($string) {
function nest(&$base) {
$result = [];
while (($ch = array_shift($base)) !== null) {
if ($ch === ')') break;
$result[] = $ch === '(' ? nest($base) : $ch;
}
if (count($result) < 2) return reset($result);
// Move operator to the end of the array:
$result[] = array_splice($result, -2, 1)[0];
return $result;
}
// split string into parts, where each bracket is a separate part
$base = preg_split("/([()])/", $string, 0, PREG_SPLIT_DELIM_CAPTURE
+ PREG_SPLIT_NO_EMPTY);
// recursively build nested postfix structure
return nest($base);
}
Вы бы назвали это так:
$result = convert($string);
Для примера ввода, приведенного в вопросе, вывод:
array (
array (
'4',
array (
'5',
'pi',
'*',
),
'+',
),
array (
'9',
array (
'3',
'sqrt',
),
'*',
),
'-',
)
Обратите внимание, что функция sqrt
также отделяется как постфиксная функция.
Смотрите, это работает на eval.in.
Я не вижу, в чем проблема с построением этого массива динамически. Например, это работает (не постфикс):
$test_array = array(
array(
"4",
array(
"5",
"pi",
"*"),
"+"),
array(
"9",
array(
"3",
"sqrt"),
"*"),
"-");
var_dump($test_array);
Таким образом, выполнение этого динамически с использованием вашего алгоритма должно вести себя подобно тому, как это делается (конечно, порядок добавления элемента зависит от вашего алгоритма):
$test_array2 = array();
$test_array2[] = array();
$test_array2[] = array();
$test_array2[] = "-";
$test_array2[1][] = "9";
$test_array2[1][] = array();
$test_array2[1][1][] = "3";
$test_array2[1][1][] = "sqrt";
$test_array2[1][] = "*";
$test_array2[0][] = "4";
$test_array2[0][] = array();
$test_array2[0][1][] = "5";
$test_array2[0][1][] = "pi";
$test_array2[0][1][] = "*";
$test_array2[0][] = "+";
var_dump($test_array2);
Оба приведенных выше примера имеют одинаковый результат.
Для универсальности и универсальности вы также можете использовать ассоциативный массив с индексами и их ролями, как в одном из {operand1, operand2 и operator}.
В самом деле, любое математическое выражение, которое вы указали выше, может иметь шаблон: «оператор операнда 1, операнд2», каким бы сложным они ни были в конце.
Пример:
5.pi будет
array('op1'=>5, 'op'=>'*', 'opd2'=>'pi');
sqrt (3) будет
array('op1' => 3, 'op' => 'sqrt', 'opd2' => null); // since sqrt is a unary function
и так далее…
Таким образом, модель была бы расширяемой, вы могли бы извлечь выгоду из семейства функций массива, касающихся индексов, не беспокоясь о порядке элементов массива, и парсер был бы, IMHO, намного проще для написания и чтения человеком, по крайней мере.