Php 解析自然语言
开始:我知道这个系统会有缺陷 注意:我添加了一些其他语言,因为我没有发现这个问题特定于php。JavaScript或jquery解决方案可以工作……我可以更改语言……这就是我想要的方法 什么:我试图解析一个字符串以确定用户想要什么 这个想法是字符串是由语音生成的 例1: 打开厨房的灯,关掉卧室和客厅的灯 例2: 把厨房的灯打开,卧室的灯打开,客厅的灯关上 例3: 关掉厨房、卧室和客厅的灯 这是一个过于简化的示例,但请注意,我希望扩展到这三个房间之外,并且只控制灯光 示例:外部吊扇打开 如何:我目前正在使用一些while循环来迭代数组,并检查数组中是否存在某些字符串 更多操作方法:我的想法是首先在“和”上拆分字符串。然后,我检查每个数组的开或关。如果它没有开或关,我就用下一个来加入数组 帮助:我很想澄清这个概念,同时看看其他人的想法……我愿意做任何事情 谢谢 JT 代码:Php 解析自然语言,php,javascript,jquery,regex,Php,Javascript,Jquery,Regex,开始:我知道这个系统会有缺陷 注意:我添加了一些其他语言,因为我没有发现这个问题特定于php。JavaScript或jquery解决方案可以工作……我可以更改语言……这就是我想要的方法 什么:我试图解析一个字符串以确定用户想要什么 这个想法是字符串是由语音生成的 例1: 打开厨房的灯,关掉卧室和客厅的灯 例2: 把厨房的灯打开,卧室的灯打开,客厅的灯关上 例3: 关掉厨房、卧室和客厅的灯 这是一个过于简化的示例,但请注意,我希望扩展到这三个房间之外,并且只控制灯光 示例:外部吊扇打开 如何:我目
$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++;
}
$input='厨房灯打开,床和生活灯关闭';
$output=preg_split(“/(and)/”,$input);
$num=(int)计数($output);
$i=0;
而我
解析自然语言并非易事,如果您想要一个真正的自然语言解析器,我建议您尝试使用现有的项目或库
话虽如此,如果你愿意限制语法和所涉及的关键字,你也许可以简化它。首先你需要知道什么是重要的——你在“地方”(卧室、厨房)有“东西”(灯、风扇),需要进入特定状态(“开”、“关”)
我会将字符串放入一个单词数组,要么使用,要么在'
上分解
现在你有了一个单词数组,从末尾开始,向后寻找一个“状态”——开或关。然后按照这个数组向后寻找一个“东西”,最后是一个“地方”。如果你到达另一个状态,那么你可以重新开始
让我尝试用伪代码来实现这一点:
// 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
}
写了这些之后,很明显,它应该使用状态机和switch语句——这表明我应该首先在纸上设计它。如果你变得更复杂,你想使用状态机来实现逻辑——状态将是“lookingForState”、“lookingForThing”等
另外,您实际上不需要将currentPlace
作为变量,但我将保留它,因为它使逻辑更加清晰
编辑
如果你想支持“打开卧室的灯”,你需要调整逻辑(如果你没有东西,你需要保存“位置”)。如果你还想支持“打开卧室的灯”,你需要更进一步
想一想,我想知道你是否能做到:
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
好的,我已经测试过了,但是由于英语的结构,出现了一些问题。问题是如果你想支持“开启…”和“开启…”,那么你需要使用我的第二个伪代码,但这并不容易,因为句子中有“和”。例如:
打开厨房的灯,关掉卧室和客厅的灯
第一个and连接两个语句,第二个and连接到位置。正确的方法是找出什么适用于什么
有两个快速选项,首先您可以坚持使用不同的单词或短语连接两个命令:
打开厨房灯,然后关闭卧室和客厅灯。
打开厨房的灯,同时关闭卧室和客厅的灯
或者,这可能更容易,您可以坚持只使用“关闭…关闭/打开”形式的命令。这适用于我上面的第一个psuedocode
第一个伪代码
请注意,如果有可能出现标点符号等,您可能需要对字符串进行大量预处理。您可能还需要考虑替换“客厅”(以及类似的两个单词短语)使用“livingroom”而不是像我这样只匹配一个单词并希望达到最佳效果。此外,代码可以简化一点,但我想让它接近psuedocode示例
编辑3
这会处理一些额外的句子,并且会得到更好的清理,它仍然依赖于每个子句末尾的“状态”,因为这是它用来作为应用操作的触发器(此版本可能会向前读取,而不是向后读取)。此外,它不会处理以下内容:
Turn my kitchen fan and my bedroom lights on and living room lights off.
你必须做一些更复杂的事情来理解“厨房”和“风扇”以及“卧室”和“灯光”之间的关系
只要输入/说出命令的人遵循一些基本规则,这些技术的一些组合可能足以完成一些令人印象深刻的任务。这当然不是最有效的解决方案,但这里有一个。你肯定可以改进它,比如缓存正则表达式,但你明白了。最后一项是每个子数组都是操作
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);
介意解释一下你使用的逻辑吗…我的意思是我在读代码,但我
我只是好奇你是否能说得更好
逻辑其实很简单,也许太简单了:
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
]
);
});
编辑:在我发布答案的时候,我还没有意识到你需要多么复杂和灵活
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
]
);
});