首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >解析自然语言

解析自然语言
EN

Stack Overflow用户
提问于 2013-09-09 00:38:04
回答 3查看 901关注 0票数 3

开始:,我知道这个系统会有缺陷!

注意:我添加了其他几种语言,因为我不认为这个问题是针对php的.一个JavaScript或jquery解决方案可以工作.我可以改变我所追求的语言...Its!

什么:,我正试图解析一个字符串,以确定用户想要什么。

这个想法是,字符串是由声音生成的。

例1:把厨房的灯打开,卧室和客厅的灯关了。

例2:把我的厨房灯、卧室灯和客厅灯都关了。

例3:把我的厨房、卧室和客厅的灯关掉。

这是一个过于简化的例子,但请注意,我想扩大到这三个房间之外,以及只是控制灯的例子:外部吊扇上。

How:,我目前正在使用几个while循环来迭代数组,并检查数组中是否有某些字符串。

More how:,我的想法是首先在"and“上的字符串上拆分。然后,我检查每个数组的on或off。如果它没有on或off,则使用next加入数组。

帮助:,我很想把这个概念搞清楚,也想看看别人的想法……我什么都想做。

谢谢JT

代码:

代码语言:javascript
复制
$input = 'kitchen lights on and bed and living lights off'; 
$output = preg_split( "/ (and) /", $input );
$num = (int)count($output);
$i=0;

while($i<$num){
    if ((strpos($output[$i],'on') !== false)||(strpos($output[$i],'off') !== false)) {}
    elseif(((strpos($output[$i+1],'on') !== false)||(strpos($output[$i+1],'off') !== false))){
    $output[$i+1] .= ' + '.$output[$i];
        unset($output[$i]);

    }

    $i++;
}
$output = array_values($output);
$i=0;
$num = (int)count($output);
echo '<br>';
while($i<$num){
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'on') !== false)&&(strpos($output[$i],'kitchen') !== false)){
echo'kitchen lights on<br>';
}
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'off') !== false)&&(strpos($output[$i],'kitchen') !== false)){
echo'kitchen lights off<br>';
}
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'on') !== false)&&(strpos($output[$i],'living') !== false)){
echo'living lights on<br>';
}
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'off') !== false)&&(strpos($output[$i],'living') !== false)){
echo'living lights off<br>';
}
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'on') !== false)&&(strpos($output[$i],'bed') !== false)){
echo'bed lights on<br>';
}
if ((strpos($output[$i],'lights') !== false)&&(strpos($output[$i],'off') !== false)&&(strpos($output[$i],'bed') !== false)){
echo'bed lights off<br>';
}   
$i++;
}

代码试用版2:备注:这将处理上述所有示例!

代码语言:javascript
复制
<?php
//works list
$inp[]='turn the lights in the bedroom on';
$inp[]='Turn on the bedroom light';
$inp[]='turn on the lights in the bedroom';
$inp[]='Turn my kitchen and my bedroom and living room lights off.';
$inp[]='Turn the light in the kitchen on and the fan in the bedroom off';
$inp[]='Turn my kitchen lights on and my bedroom and living room lights off';
$inp[]='Turn my kitchen fan and my bedroom lights on and living room lights off.';
$inp[]='Turn my kitchen lights on and my bedroom lights on and living room lights off';
$inp[] = 'kitchen lights on and bath and living lights off'; 
$inp[] = 'flip on the lights in the living room';
$inp[] = 'turn on all lights';

//does not work list
//$inp[] = 'turn on all lights but living';

foreach ($inp as $input){

$input = trim($input);
$input  = rtrim($input, '.');
$input = trim($input);
$input  = rtrim($input, '.');


$words = explode(" ", $input);

$state = array('and','but','on','off','all','living','bed','bedroom','bath','kitchen','dining','light','lights','fan','tv');
$result = array_intersect($words, $state);
$result = implode(" ", $result);
$result = trim($result);
    //$result = preg_split('/(and|but)/',$input,-1, PREG_SPLIT_DELIM_CAPTURE);
$result = preg_split( "/ (and|but) /",  $result );
    //$result = explode("and", $result);

$sep=array();

foreach($result as $string){
$word = explode(" ", $string);
$sep[]=$word;   
}

$test=array();
$num = (int)count($sep);

$i=0;

while($i<($num)){   
$result = (int)count(array_intersect($sep[$i], $state));    
$j=$i;

    while($result<=3)
    {
        $imp = implode(" ", $sep[$j]);
        if(isset($test[$i])){$test[$i]=$imp.' '.$test[$i];}
        else{$test[$i]=$imp;}

        if ($result>=3){$j++;break;}        
        $result = (int)count(array_intersect($sep[++$j], $state));      
    }
$i=$j;
}

print_r($test);
    echo '<br>';
}


?>
EN

回答 3

Stack Overflow用户

发布于 2013-09-09 02:04:43

解析自然语言并不简单,如果您想要一个真正的自然语言解析器,我建议您尝试使用现有的项目或库。这是一个基于基于web的解析器斯坦福分析器。或者维基百科是一个很好的起点。

话虽如此,如果您愿意限制语法和所涉及的关键字,您可能可以简化它。首先,你需要知道什么是重要的--在“场所”(卧室,厨房)中有“东西”(灯,风扇),需要进入特定的状态(“打开”,“关闭”)。

我会将字符串放入一个单词数组中,要么使用托克,要么在' '上爆炸。

现在你有了一系列的单词,从结尾开始,然后回溯,寻找一个“状态”--打开或关闭。然后向后走,寻找“事物”,最后是“地方”。如果你进入另一种状态,你就可以重新开始。

让我试着用伪码来做:

代码语言:javascript
复制
// array of words is inArray
currentPlace = null;
currentThing = null; 
currentState = null;
for (i = (inArray.length - 1); i >= 0; i--) {
    word = inArray[i];

    if (isState(word)) {

      currentState = word;
      currentPlace = null;
      currentThing = null;

    } else if (currentState) {

        if (isThing(word)) { 

             currentThing = word;
             currentPlace = null;

        } else if (currentThing) { 

             if (isPlace(word)) { 
                 currentPlace = word
                 // Apply currentState to currentThing in currentPlace
             }
             // skip non-place, thing or state word. 
        }
        // Skip when we don't have a thing to go with our state

    } 
    // Skip when we don't have a current state and we haven't found a state
}

写了这篇文章之后,很明显,它应该使用状态机和开关语句--这表明我应该首先在纸上设计它。如果您变得更加复杂,您希望使用状态机来实现逻辑--状态将是“查找状态”、“查找内容”等等。

而且,您并不真正需要currentPlace作为变量,但我将保留它,因为它使逻辑更加清晰。

编辑

如果你想支持“打开卧室里的灯”,你需要调整逻辑(如果你没有东西的话,你需要保存“位置”)。如果你还想支持“打开卧室里的灯”,你还需要更进一步。

想一想,我不知道你能不能:

代码语言:javascript
复制
have a currentState variable and arrays for currentPlace and currentThing
for each word 
    if it's a state:
        store it in currentState 
    if it's a thing, or place:
        add it to the approriate array
        if currentState is set and there is content in currentPlaces and currentThings:
            apply currentState to all currentThings in all currentPlaces

这还不是很清楚,但其中一个实现可能会给您一个起点。

编辑2

好的,我测试了它,因为英语的结构方式有一些问题。问题是如果你想支持“打开.”和“打开.打开”之后,您需要使用我的第二个伪代码,但是这并不容易使用,因为‘并且在句子中。例如:

打开我的厨房灯,我的卧室客厅的灯关了。

第一个和连接两个语句,第二个和联接到places。正确的方法是通过把句子画成图来确定什么是适用于什么。

有两个快速选项,首先,您可以坚持使用不同的单词或短语来连接两个命令:

打开我的厨房灯,然后我的卧室客厅的灯关了。把厨房的灯打开,卧室的的客厅灯也关了。

或者,这可能更容易一些,您可以坚持只使用表单“.off/ on”的命令。这适用于我上面的第一个psuedocode。

第一个psuedocode的JavaScript实例

注意,如果有任何标点符号的可能,你可能需要对字符串进行大量的预处理,等等。你也可能想把“客厅”(和类似的两个单词)替换为“起居室”,而不是仅仅匹配一个单词,并希望像我所做的那样做到最好。此外,代码也可以简化一些,但我希望将其保持在psuedocode示例附近。

编辑3

新Javascript示例

这处理了一些额外的句子,并被清理得更好一些,它仍然依赖于每个子句末尾的“state”,因为它使用它作为触发器来应用这些操作(这个版本可能会向前读,而不是向后读)。此外,它也不会处理以下内容:

代码语言:javascript
复制
Turn my kitchen fan and my bedroom lights on and living room lights off.

你必须做一些更复杂的事情来理解“厨房”与“风扇”、“卧室”和“灯光”之间的关系。

这些技术的结合可能足以使人印象深刻,只要输入/说命令的人都遵循一些基本规则。

票数 3
EN

Stack Overflow用户

发布于 2013-09-09 02:07:23

这当然不是最有效的解决方案,但这里有一个。您肯定可以对其进行改进,比如缓存正则表达式,但是您有了这个想法。每个子数组中的最后一个项是操作。

演示

代码语言:javascript
复制
var s = 'Turn my kitchen lights on and my bedroom lights on and living room lights off and my test and another test off',
    r = s.replace(/^Turn|\s*my/g, '').match(/.+? (on|off)/g).map(function(item) {
        var items = item.trim().replace(/^and\s*/, '').split(/\s*and\s*/),
            last = items.pop().split(' '),
            op = last.pop();
        return items.concat([last.join(' '), op]);
    });

console.log(r);

介意解释一下你使用的逻辑..。我是说我读了代码,但我只是好奇你能不能说得更好

逻辑其实很简单,也许太简单了:

代码语言:javascript
复制
var s = 'Turn my kitchen lights on and my bedroom lights on and living room lights off and my test and another test off',
    r = s
        .replace(/^Turn|\s*my/g, '') //remove noisy words
        .match(/.+? (on|off)/g) //capture all groups of [some things][on|off]
        //for each of those groups, generate a new array from the returned results
        .map(function(item) {
            var items = item.trim()
                    .replace(/^and\s*/, '') //remove and[space] at the beginning of string
                    //split on and to get all things, for instance if we have
                    //test and another test off, we want ['test', 'another test off']
                    .split(/\s*and\s*/),
                //split the last item on spaces, with previous example we would get
                //['another', 'test', 'off']
                last = items.pop().split(' '),
                op = last.pop(); //on/off will always be the last item in the array, pop it
            //items now contains ['test'], concatenate with the array passed as argument
            return items.concat(
                [
                    //last is ['another', 'test'], rejoin it together to give 'another test'
                    last.join(' '),
                    op //this is the operation
                ]
            );
        });

编辑:在我发布答案的时候,我还没有意识到你需要这样做是多么的复杂和灵活。我提供的解决方案只适用于像我的例子中那样的句子结构,包含可识别的嘈杂单词和特定的命令顺序。对于更复杂的内容,您将别无选择,只能创建一个像@SpaceDog建议的解析器。只要我有足够的时间,我就会设法想出点什么来。

票数 3
EN

Stack Overflow用户

发布于 2015-04-29 18:39:19

我一直在编写解析菜单和菜谱 (尚未完成),这是我的方法:

  • 查找句子分隔符(我使用和其他)
  • 分析每个句子,找出你需要的key单词(电灯/灯泡/等.,开/关)
  • 如果你有一套有限的地方(厨房,浴室等),
    • 搜索这些关键字,删除其他关键字
    • 否则
    • 删除某些人可能使用的extra words (明亮、彩色等)

  • 将其存储到一个数组中,如下所示:
    • 什么
    • 哪里

  • 如果您没有其中一个字段,请将其保留为空白。
  • 对于每个结果,检查您所拥有的内容,如果您有一个空白字段,则用前面的解析填充它。

把卧室和厨房的灯打开

  • 1:
    • 把卧室里的灯打开
    • 什么:灯亮着
    • 地点:卧室

  • 2:
    • 在厨房里
    • 什么:
    • 地点:厨房

what_2为空,what_2lights on

请记住,有时需要用下一个结果填充数组(这取决于句子的结构方式,但很少见),我在数组中添加了"+“或"-”,这样我就知道在解析时是否需要向前或向后查找缺少的部分。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18690083

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档