#php #regex #parsing
#php #регулярное выражение #синтаксический анализ
Вопрос:
Я создаю telegram-бота, и очень сложно получить входное значение из строки. Моя цель — сделать мою команду простой в написании и понятной. Это пример команды, которую я получил из сообщения клиента
,simpleImage. query Dark background. width 200. height 200. text %fortune_teller%
Это должен быть массив, подобный этому
[simple_image][query] => 'Dark background'
[simple_image][width] => '200'
[simple_image][height] => '200'
[simple_image][text] => '%fortune_teller%'
и для пустого аргумента должно выглядеть так
,sayHello. %custom_id%
[say_hello] => '%custom_id%'
Но у меня возникает некоторая проблема, когда я пытаюсь ввести какой-нибудь японский текст и специальный символ, например , *, amp;, |, et cetera
на
,cmd. cat files.txt 2>/dev/null amp;amp; find $HOME -type f -iname *.mp3 -delete
Это некоторый код, который я пишу до сих пор
<?php
function parse($string) {
preg_match_all("/,?([a-z_] )?..([a-z] )s([a-zs%_] )/", $string, $tmp);
$query = array_combine($tmp[2], $tmp[3]);
if(!empty($tmp[1])) {
return array_merge([$tmp[1][0]=>true], $query);
}
}
var_dump(parse($update['message']));
Комментарии:
1. Каким должен быть результат ввода, который не работает? Почему здесь нет точек, как в вашем первом примере? И почему
simple_image
в результирующем массиве для вашего первого примера, когда имя командыsimpleImage
?2. Это мой следующий план замены верхнего регистра на подчеркивание нижний регистр, у меня проблема с синтаксическим анализом, когда я попытался ввести несколько специальных символов в юникоде, это не сработало, возвращая null из array_merge
3. Нет, я имею в виду, что в вашем первом примере ваши аргументы кажутся разделенными точками (
.
символом). Во втором случае это не так. Каковы правила для синтаксического анализа ваших команд? Это довольно неясно, основываясь на этих двух примерах. Также, опять же, пожалуйста, четко покажите, каким должен быть результат для этого второго.4. О
..
, извините, я забыл об этом, но я уверен, что имя метода с префиксом запятой и точкой в конце не работает для строки командной оболочки, я ищу библиотеки анализатора команд в packagist, но для этих проблем ничего не подходит. Позвольте мне отредактировать, кстати
Ответ №1:
Я практически никогда не рекомендую именованные группы захвата, потому что они просто раздувают шаблон и выходной массив совпадений, но для тех, кто предпочитает их, вы можете использовать это:
~(?:^,(?<COMMANDS>[^.] )|G(?!^)).(?= )(?: (?<KEYS>S ))? (?<VALUES>. ?(?=. |$))~
В противном случае:
~~(?:^,([^.] )|G(?!^)).(?= )(?: (S ))? (. ?(?=. |$))~~
По сути, вы должны использовать G
(продолжить метасимвол), чтобы продолжить сопоставление переменного числа последовательностей после начальной командной подстроки. Мой шаблон основан на том факте, что команда и последующие пары ключ-значение разделены точками, за которыми сразу следует пробел. Если вы не можете на 100% полагаться на эту последовательность разделителей, то вам необходимо решить эту проблему, прежде чем пытаться двигаться дальше.
Как только у вас будет массив matches (Demo), вам просто нужно повторить его, чтобы построить желаемую структуру вывода.
Код: (демо)
$commands = [
',simpleImage. query Dark background. width 200. height 200. text %fortune_teller%',
',sayHello. %custom_id%',
',cmd. cat files.txt 2>/dev/null amp;amp; find $HOME -type f -iname *.mp3 -delete',
];
foreach ($commands as $command) {
$result = [];
if (preg_match_all('~(?:^,([^.] )|G(?!^)).(?= )(?: (S ))? (. ?(?=. |$))~', $command, $out)) {
foreach ($out[2] as $index => $subKey) {
if (strlen($subKey)) {
$result[$out[1][0]][$subKey] = $out[3][$index];
} else {
$result[$out[1][0]] = $out[3][$index];
}
}
}
echo var_export($result, true) . "n---n";
}
Вывод:
array (
'simpleImage' =>
array (
'query' => 'Dark background',
'width' => '200',
'height' => '200',
'text' => '%fortune_teller%',
),
)
---
array (
'sayHello' => '%custom_id%',
)
---
array (
'cmd' =>
array (
'cat' => 'files.txt 2>/dev/null amp;amp; find $HOME -type f -iname \*.mp3 -delete',
),
)
---