Самый эффективный способ сопоставления команд при разработке чат-бота?

Я создаю простого чат-бота через API Messenger Platform, и я в значительной степени застрял в том, как эффективно распознавать набор команд, на которые бот может реагировать. В настоящее время я использую оператор switch для обнаружения команд, начинающихся с восклицательного знака (например,! Showlist;! Additem <single/set of parameter(s)>).

Вот что у меня сейчас есть:

switch(true){
case stristr($receivedMsg,'!additem'):
....
}

На любом этапе сопоставления код либо выполняет набор операторов, либо сначала экстраполирует возможные параметры, а затем выполняет с ними некоторые операторы.

Проблемы с вышеупомянутой установкой следующие:

  • в случае команд без параметров можно получить соответствующий код для выполнения, даже если команда написана с ошибкой. Например. ! additem # $ %% будет по-прежнему вызывать фактический код команды в операторе switch.
  • в случае команд, которые принимают параметры, при извлечении этих параметров с помощью следующего оператора:

    $item=str_replace('!additem', '', $receivedMsg);
    

    очень легко включить нежелательный текст в параметры; вы можете иметь дело с пробелами с trim() или подразумевать, что всегда будет пробел, и отредактируйте вышеприведенный оператор, чтобы включить его в функцию. Например.

    $item=str_replace('!additem ', '', $receivedMsg);
    

    но это создает другую проблему при попытке отделить команду от параметров.

Я знаю, что решением может быть жесткое кодирование с помощью систематических функций манипуляции со строками, но мне это не кажется правильным. Что люди делают в этой ситуации? Разве нет конкретного способа точно сопоставить команды и надежно определить возможные опечатки пользователей?

1

Решение

Вы не работали с регулярными выражениями в своем собственном решении, но пометили его правильно. От stristr() Я обнаружил, что вы не ищете новых команд, поэтому применил ту же логику к RegEx:

$msg = 'Gonna add it !additem param1,param2';
preg_match('~(!\S+)\s*(.*)~', $msg, $match);
$command = $match[1];
$parameters = preg_split('~\s*,\s*~', $match[2]);

Я пытался сделать это в одну строку, но позже подумал, что это будет намного чище. Кстати, мне интересно, о заявлении переключателя.

Распределение RegEx:

~   # regex delimiter
(   # Start of Capturing Group (1)
!\S+    # Match non-space characters that start with !
)   # End of CG1
\s* # Any number of white-sapce characters
(   # Start of CG2
.*  # Match up to end
)   # End of CG2
~   # regex delimiter

preg_split тоже получает регулярное выражение в качестве первого аргумента и пытается разделить его, почти explode с регулярным выражением \s*,\s* означает запятую, которая может быть заключена в любое количество пробелов.

1

Другие решения

if ($receivedMsg[0] == '!')
switch (strtolower(substr(reset(explode(' ', $receivedMsg)), 1)))
{
case 'additem':
// do this
break;
case 'delitem':
// do that
break;
default:
echo 'Command not recognized.';
}

Ну, это один из способов сделать это. Вы также можете объявить массив с функциями, которые обрабатывают каждую команду, например:

$handles = [
'additem' = function ($args) { /* add something */ },
'delitem' = function ($args) { /* del something */ },
// ...
];

if ($receivedMsg[0] == '!')
{
$args = explode(' ', $receivedMsg);
$cmd  = strtolower(substr($args[0], 1));
if (isset($handles[$cmd]))
$handles[$cmd]($args);
else
echo 'Command not recognized.';
}
1

Основываясь на моем решении на основе ответов, предоставленных @Havenhard и @revo, я написал следующее решение, которое идеально подходит для меня:

$this->senderId = $messaging['sender']['id'];
$command_handlers = [
'additem' => "addItemCommand",
'showlist' => "showListCommand",
'rngroup' => "renameGroupCommand"];

$actionCompletedOrh = new OutRequestHandler($this->senderId);

if(!empty($messaging['message']) && empty($messaging['message']['quick_reply'])){
$receivedMsg = $messaging['message']['text'];
$replyMsg = "";
$this->performSenderAction(0);
//isCommand uses this regex to perform the evaluation
//(^!\w+\s+([\w,\s]*$)|^!\w+$)"if($this->isCommand($receivedMsg)){
//regex matching to get params in raw form
preg_match("~(^!\w+\s+([\w,\s]*$)|^!\w+$)~",$receivedMsg,$match);
//regex matching to get the command
preg_match("~^!\w+~",$match[0],$_match);
$command = strtolower($_match[0]);
$params = null;
if(count($match)>2){
//the function below uses preg_split as in @revo's example
$params = $this->getCommandParams($match[2]);
}
if(array_key_exists(substr($command,1), $command_handlers)){
$func = $command_handlers[substr($command,1)];
$replyMsg=$this->$func($params,$connection);
}
else{
$replyMsg=$this->getPromptMessage("cmer1");
}
}
else{
//All other messages - possibly processed with NPL
}
$this->performSenderAction(2);
$replyMsg = json_encode($replyMsg);
$actionCompletedOrh->sendJustTextMessage($replyMsg,$access_token);
}

Вы видите что-нибудь, что я мог бы улучшить? Пожалуйста, дайте мне знать, что и почему в комментариях!

0