在开发聊天机器人时匹配命令的最有效方法是什么?

时间:2018-02-10 17:09:35

标签: php regex string string-matching chatbot

我正在通过Messenger Platform API创建一个简单的聊天机器人,我几乎坚持如何有效地识别机器人可以做出反应的一组命令。我目前正在使用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);
    

    但是当尝试将命令与params分开时,会出现其他问题。

我知道解决方案可能是使用系统字符串操作函数进行硬编码,但这对我来说似乎并不正确。人们在这种情况下做了什么?是不是有一种特定的方法来完全匹配命令并安全地发现最终用户&#39;错别字?

3 个答案:

答案 0 :(得分: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 :(得分: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.';
}

答案 2 :(得分:0)

基于我对@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);
    }

你看到我能改进的东西吗?请让我知道评论中的内容和原因!