字符串键短语匹配


String key phrase matching

在莱文斯坦how are you中,hw r uhow are uhw ar you可以比较为相同,

无论如何我可以实现这一点

如果我有一个短语喜欢。

短语

嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?

短语

我叫布鲁斯。

关键短语

你叫什么名字

响应

我的名字是蝙蝠侠。

我从用户那里获取输入。我有一个表格,其中包含带有响应的可能请求列表。例如,用户会询问"它的名字",有没有办法检查一个句子是否有像What is your name这样的关键短语,如果找到它,它将返回可能的响应

喜欢

phrase = ' hi, my name is john doe. I live in new york. What is your name?'
 
//I know this one will work
if (strpos($phrase,"What is your name") !== false) {
    return $response;
}
//but what if the user mistype it 
if (strpos($phrase,"Wht's your name") !== false) {
    return $response;
}

我有办法做到这一点吗? Levenstein 只有在比较字符串的字符串长度不是那么长的情况下才能完美工作。

喜欢

嗨,你的名字

我的名字是蝙蝠侠。

但如果它这么长

嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?

如果有较短

的短语,它将识别距离较短的较短短语并返回错误的响应

我在想另一种方法是检查一些关键短语。 那么有什么想法可以实现这个吗?

我正在做这样的事情,但也许我认为有一种更好和正确的方法

$samplePhrase = 'hi, im spongebob, i work at krabby patty. i love patties. Whts your name my friend';
$keyPhrase = 'What is your name';
  1. 获取keyPhrase的第一个字符。那将是"W"迭代通过
  2. $samplePhrase字符并与keyPhrase的第一个字符进行比较
  3. h,i, ,i,m, ,s,p等等。
  4. 如果keyPhrase.char = samplePhrase.currentChar
  5. get keyPhrase.length
  6. 获取示例短语.当前字符索引
  7. 获取基于当前字符索引的 samplePhrase 的子字符串到 keyPhrase.length
  8. 它将得到的第一个将是work at krabby pa
  9. 使用莱文斯蒂安距离将work at krabby pa与$keyPhrase("你叫什么名字")进行比较
  10. 并更好地检查它,请使用semilar_text。11.如果不相等,距离是大重复过程。

我的建议是从关键短语生成 n 元语法列表,并计算每个 n 元语法和关键短语之间的编辑距离。

例:

key phrase: "What is your name"
phrase 1: "hi, my name is john doe. I live in new york. What is your name?"
phrase 2: "My name is Bruce. wht's your name"

可能的匹配 n-gram 长度在 3 到 4 个单词之间,因此我们为每个短语创建所有 3 克和 4 克,我们还应该通过删除标点符号和小写所有内容来规范字符串。

phrase 1 3-grams:
"hi my name", "my name is", "name is john", "is john doe", "john doe I", "doe I live"... "what is your", "is your name"
phrase 1 4-grams:
"hi my name is", "my name is john doe", "name is john doe I", "is john doe I live"... "what is your name"
phrase 2 3-grams:
"my name is", "name is bruce", "is bruce wht's", "bruce wht's your", "wht's your name"
phrase 2 4-grmas:
"my name is bruce", "name is bruce wht's", "is bruce wht's your", "bruce wht's your name"

接下来,您可以在每个 n 元语法上做列文斯坦距离,这应该可以解决您上面介绍的用例。 如果您需要进一步规范化每个单词,您可以使用语音编码器,例如Double Metaphone或NYSIIS,但是,我对所有"常见"语音编码器进行了测试,在您的情况下,它没有显示出显着的改进, 拼音编码器更适合名称。

我对PHP的经验有限,但这里有一个代码示例:

<?php
function extract_ngrams($phrase, $min_words, $max_words) {
    echo "Calculating N-Grams for phrase: $phrase'n";
    $ngrams = array();
    $words  = str_word_count(strtolower($phrase), 1);
    $word_count = count($words);
    for ($i = 0; $i <= $word_count - $min_words; $i++) {
        for ($j = $min_words; $j <= $max_words && ($j + $i) <= $word_count; $j++) {
            $ngrams[] = implode(' ',array_slice($words, $i, $j));
        }
    }
    return array_unique($ngrams);
}
function contains_key_phrase($ngrams, $key) {
    foreach ($ngrams as $ngram) {
        if (levenshtein($key, $ngram) < 5) {
            echo "found match: $ngram'n";
            return true;
        }
    }
    return false;
}
$key_phrase = "what is your name";
$phrases = array(
        "hi, my name is john doe. I live in new york. What is your name?",
        "My name is Bruce. wht's your name"
        );
$min_words = 3;
$max_words = 4;
foreach ($phrases as $phrase) {
    $ngrams = extract_ngrams($phrase, $min_words, $max_words);
    if (contains_key_phrase($ngrams,$key_phrase)) {
        echo "Phrase [$phrase] contains the key phrase [$key_phrase]'n";
    }
}
?>

输出是这样的:

计算短语的 N 元语法:嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?找到匹配项:你叫什么名字短语[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?包含关键短语 [你叫什么名字]计算短语的 N 元语法:我的名字是布鲁斯。你的名字找到匹配项:WHT 是你的名字短语 [我的名字是布鲁斯。 你的名字] 包含关键短语 [你叫什么名字]

编辑:我注意到一些建议,即在生成的n-gram中的每个单词中添加语音编码。我不确定语音编码是这个问题的最佳答案,因为它们大多调整为词干名称(美国、德国或法国,取决于算法),并且不太擅长对普通单词进行词干提取。

我实际上写了一个测试来在 Java 中验证这一点(因为编码器更容易获得),这是输出:

===========================创建新的语音匹配器    引擎:洞穴电话2    关键词:你叫什么名字    编码关键词:WT11111111 AS11111111 YA11111111 NM11111111找到匹配项:[你叫什么名字?编码:WT11111111 AS11111111 YA11111111 NM11111111短语:[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?匹配:真短语:[我的名字是布鲁斯。===========================创建新的语音匹配器    引擎:双手机    关键词:你叫什么名字    编码的关键短语:作为 AR NM找到匹配项:[什么是您的] 编码:AT 作为 AR短语:[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?匹配:真找到匹配项:[你的名字] 编码:ATS AR NM短语:[我的名字是布鲁斯。===========================创建新的语音匹配器    引擎: 尼西斯    关键词:你叫什么名字    编码关键词:WAT I YAR NAN找到匹配项:[你叫什么名字?编码:WAT I YAR NAN短语:[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?匹配:真找到的匹配项:[你的名字] 编码:WT YAR NAN短语:[我的名字是布鲁斯。===========================创建新的语音匹配器    引擎:桑德克斯    关键词:你叫什么名字    编码关键词: W300 I200 Y600 N500找到匹配项:[你叫什么名字?编码: W300 I200 Y600 N500短语:[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?匹配:真短语:[我的名字是布鲁斯。===========================创建新的语音匹配器    引擎:RefinedSoundex    关键词:你叫什么名字    编码关键词: W06 I03 Y09 N8080找到匹配项:[你叫什么名字?编码:W06 I03 Y09 N8080短语:[嗨,我的名字是约翰·多伊。我住在纽约。你叫什么名字?匹配:真找到匹配项:[你的姓名] 编码:W063 Y09 N8080短语:[我的名字是布鲁斯。

在运行这些测试时,我使用了 levenshtein 距离 4,但我很确定您可以找到使用拼音编码器无法正确匹配的多种边缘情况。 通过查看示例,您可以看到,由于编码器完成的词干提取,以这种方式使用它们时,实际上更有可能出现误报。 请记住,这些算法最初旨在找到人口普查中那些名字相同并且实际上哪个英语单词"听起来"相同的人。

您要实现的是一个相当复杂的自然语言处理任务,通常需要解析等内容。

我的建议是创建一个句子分词器,将短语拆分为句子。然后标记每个句子,在空格,标点符号上拆分,并且可能还将一些缩写重写为更正常的形式。

然后,您可以创建自定义逻辑,遍历每个句子的标记列表以查找特定含义。 例如:['...','什么','...','...','你的','姓名','...','...','?','...','?','?',','...'这句话可以是"那么,你到底叫什么名字?"或者"你叫什么名字?"

我正在添加代码作为示例。我并不是说你应该使用这么简单的东西。下面的代码使用 NlpTools 一个 php 中的自然语言处理库(我参与了该库,所以请随意假设我有偏见)。

 <?php
 include('vendor/autoload.php');
 use 'NlpTools'Tokenizers'ClassifierBasedTokenizer;
 use 'NlpTools'Classifiers'Classifier;
 use 'NlpTools'Tokenizers'WhitespaceTokenizer;
 use 'NlpTools'Tokenizers'WhitespaceAndPunctuationTokenizer;
 use 'NlpTools'Documents'Document;
 class EndOfSentence implements Classifier
 {
     public function classify(array $classes, Document $d)
     {
         list($token, $before, $after) = $d->getDocumentData();
         $lastchar = substr($token, -1);
         $dotcnt = count(explode('.',$token))-1;
         if (count($after)==0)
             return 'EOW';
         // for some abbreviations
         if ($dotcnt>1)
             return 'O';
         if (in_array($lastchar, array(".","?","!")))
             return 'EOW';
     }
 }
 function normalize($s) {
     // get this somewhere static
     $hash_table = array(
         'whats'=>'what is',
         'whts'=>'what is',
         'what''s'=>'what is',
         '''s'=>'is',
         'n''t'=>'not',
         'ur'=>'your'
         // .... more ....
     );
     $s = mb_strtolower($s,'utf-8');
     if (isset($hash_table[$s]))
         return $hash_table[$s];
     return $s;
 }
 $whitespace_tok = new WhitespaceTokenizer();
 $punct_tok = new WhitespaceAndPunctuationTokenizer();
 $sentence_tok = new ClassifierBasedTokenizer(
     new EndOfSentence(),
     $whitespace_tok
 );
 $text = 'hi, my name is john doe. I live in new york. What''s your name? whts ur name';
 foreach ($sentence_tok->tokenize($text) as $sentence) {
     $words = $whitespace_tok->tokenize($sentence);
     $words = array_map(
         'normalize',
         $words
     );
     $words = call_user_func_array(
         'array_merge',
         array_map(
             array($punct_tok,'tokenize'),
             $words
         )
     );
     // decide what this sequence of tokens is
     print_r($words);
 }

您可以考虑使用 soundex 函数将输入字符串转换为语音等效的书写,然后继续搜索。soundex

首先修复所有短代码示例 wht 而不是 whats

$txt=$_POST['txt']
$txt=str_ireplace("hw r u","how are You",$txt);
$txt=str_ireplace(" hw "," how ",$txt);//remember an space before and after phrase is required else it will replace all occurrence of hw(even inside a word if hw exists).
$txt=str_ireplace(" r "," are ",$txt);
$txt=str_ireplace(" u "," you ",$txt);
$txt=str_ireplace(" wht's "," What is ",$txt);

同样,根据需要添加任意数量的短语。现在只需检查本文中的所有可能问题并了解他们的立场

if (strpos($phrase,"What is your name")) {//No need to add "!=" false
    return $response;
}