简体   繁体   English

开发聊天机器人时最有效的命令匹配方式?

[英]Most effective way to match commands when developing a chatbot?

I'm creating a simple chatbot through the Messenger Platform API and I'm pretty much stuck on how to effectively recognise a set of commands that the bot can react to. 我正在通过Messenger平台API创建一个简单的聊天机器人,并且在如何有效地识别该机器人可以响应的一组命令方面,我一直处于僵局。 I'm currently using a switch statement to detect commands that begin with an exclamation mark (eg !showlist; !additem <single/set of parameter(s)> ). 我目前正在使用switch语句来检测以感叹号开头的命令(例如!showlist;!additem <single/set of parameter(s)> )。

Here is what I currently have: 这是我目前拥有的:

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

At any matching stage the code, either execute a set of statements or extrapolate the eventual parameters first and then executes some statements with them. 在任何匹配阶段,代码都将执行一组语句或首先推断最终参数,然后使用它们执行某些语句。

The issues I'm having with the above setup are the following: 我在上述设置中遇到的问题如下:

  • in case of no parameters commands it is possible to get the related code to execute even if the command is misspelled. 在没有参数命令的情况下,即使命令拼写错误,也可以使相关代码执行。 Eg !additem#$%% will still invoke the actual command's code in the switch statement. 例如,!additem#$ %%仍将在switch语句中调用实际命令的代码。
  • in case of commands that take parameters, when retrieving those parameters with say this statement: 如果命令带有参数,则在使用以下语句检索这些参数时:

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

    it is very easy to include unwanted text in the parameters; 在参数中包含不需要的文本非常容易; you may deal with spaces with trim() or imply there will always be a space and edit the above statement to include it in the function. 您可以使用trim()处理空格,或者暗示总会有一个空格,然后编辑以上语句以将其包含在函数中。 Eg 例如

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

    but this makes other problem arise when trying to separate the command from the params. 但这在尝试将命令与参数分开时会引起其他问题。

I'm aware that a solution could be hardcoding with systematic string manipulation functions but that doesn't seem correct to me. 我知道一个解决方案可能是使用系统的字符串操作功能进行硬编码,但对我来说似乎并不正确。 What do people do in this situation? 人们在这种情况下会做什么? Isn't there a specific way to exactly match commands and securely spot eventual users' typos? 是否没有特定的方法可以完全匹配命令并安全地发现最终用户的错别字?

You didn't work with Regular Expressions in your own solution but tagged it correctly. 您没有在自己的解决方案中使用正则表达式,但已正确对其进行了标记。 By stristr() function I found you are not looking for more coming commands so I applied the same logic onto RegEx: 通过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]);

I tried to do it a one-liner but later thought this would be much more cleaner. 我试着做一个单线,但后来认为这会更清洁。 BTW I wonder about the switch statement. 顺便说一句,我想知道switch语句。

RegEx Breakdown: 正则表达式细分:

~   # 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 too receives a regex as its first argument and tries to split on it, almost a explode with regex. preg_split也将正则表达式作为其第一个参数,并尝试对其进行拆分,这几乎与正则表达式发生了explode \\s*,\\s* means a comma that may be enclosed in any number of spaces. \\s*,\\s*表示可以用任意多个空格括起来的逗号。

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.';
    }

Well that's one way to do it. 嗯,这是做到这一点的一种方法。 You can also declare an array with the functions that handle each command, example: 您还可以使用处理每个命令的函数声明一个数组,例如:

$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.';
}

Basing my solution on the answers that @Havenhard and @revo provided, I've written the following solution that perfectly works for me: 基于@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);
    }

Do you see anything I could improve? 您看到我能改善的地方吗? Please let me know what and why in the comments! 请在评论中让我知道什么以及为什么!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM