我正在编写一个试图从自然语言中获取意义的程序.程序将接受一个字符串,并查看它是否包含某些单词组合.有关示例,请参阅以下代码段:
if (phrase.contains("turn")) { // turn something on/off
if (phrase.contains("on") && !phrase.contains("off")) { // turn something ON
if (phrase.contains("pc") || phrase.contains("computer")) // turn on computer
turnOnComputer();
else if (phrase.contains("light") || phrase.contains("lamp")) // turn on lights
turnOnLights();
else
badPhrase();
}
else if (phrase.contains("off") && !phrase.contains("on")) { // turn something OFF
if (phrase.contains("pc") || phrase.contains("computer")) // turn off computer
turnOffComputer();
else if (phrase.contains("light") || phrase.contains("lamp")) // turn off lights
turnOffLights();
else
badPhrase();
}
else {
badPhrase();
}
}
else {
badPhrase();
}
正如您所看到的,如果我想要解释的不仅仅是一些含义,这很快就会成为无法管理的代码.我怎样才能更好地管理这个?
解决方法:
首先,我不确定您的方法对自然语言处理的适用性.此外,还没有现有的NLP库吗?特别是在NLP中,我知道有时候顺序和词性很重要,加上这种方法对于单词变化不是很强大.
但是,如果你想坚持你的方法,一个让它更具可读性和更易维护的想法(见下面的更全面的优点/缺点)是这样的:
StringFinder finder = new StringFinder(phrase);
if (finder.containsAll("turn", "on").andOneOf("computer", "pc").andNot("off").matches()) {
turnOnComputer();
return;
} else if (finder.containsAll("turn", "off").andOneOf("computer", "pc").andNot("on").matches()) {
turnOffComputer();
return;
} else if (finder.containsAll("turn", "on").andOneOf("light", "lamp").andNot("off").matches()) {
...
} else if (finder.containsAll("turn")) { // If we reached this point
badPhrase();
} else if (...
有类似的东西:
class StringFinder {
private final String phrase;
private final Map cache = new HashMap();
public StringFinder(String phrase) { this.phrase = phrase; }
public StringFinder containsAll(String... strings) {
for (String string : strings) {
if (contains(string) == false) return new FailedStringFinder(phrase);
}
return this;
}
public StringFinder andOneOf(String... strings) {
for (String string: strings) {
if (contains(string)) return this;
}
return FailedStringFinder(phrase);
}
public StringFinder andNot(String... strings) {
for (String string : strings) {
if (contains(string)) return new FailedStringFinder(phrase);
}
return this;
}
public boolean matches() { return true; }
private boolean contains(String s) {
Boolean cached = cache.get(s);
if (cached == null) {
cached = phrase.contains(s);
cached.put(s, cached);
}
return cached;
}
}
class FailedStringFinder extends StringFinder {
public boolean matches() { return false; }
// The below are actually optional, but save on performance:
public StringFinder containsAll(String... strings) { return this; }
public StringFinder andOneOf(String... strings) { return this; }
public StringFinder andNot(String... strings) { return this; }
}
缺点:
>重复检查:多次检查“转弯”.
>重复模式(但见下面的优点).
好处:
>相对简洁的代码.
>检查重复但缓存,因此性能仍然很高.
>条件非常接近操作,导致代码非常易读.
>不嵌套条件允许在不重构代码的情况下更改特定操作所需的条件,从而导致更多可维护的代码.
>易于更改条件和操作的顺序,以控制优先级.
>缺乏嵌套使得将来更容易并行化.
>灵活的条件检查:例如,您可以向StringFinder添加方法以匹配重复检查,例如:public StringFinder containsOnAndNotOff(){return containsAll(“on”).andNot(“off”); },或匹配您需要的一些奇特的条件,例如andAtLeast3Of(String … strings){…}.
>缓存还可以扩展到不仅记住单词是否出现,还要记住是否出现整个模式.
>您还可以添加最终条件:andMatches(Pattern p)(使用正则表达式模式) – 实际上,您可以使用正则表达式对许多其他检查进行建模.然后它可以很容易地缓存 – 而不是使用字符串作为键,使用模式.
标签:java,parsing,string
来源: https://codeday.me/bug/20190612/1229221.html