对于解析播放器命令,我最常使用split方法通过分隔符拆分字符串,然后通过一系列if
s 或switch
es 找出其余部分。在 Java 中解析字符串有哪些不同的方法?
15 回答
我真的很喜欢正则表达式。只要命令字符串相当简单,您就可以编写一些正则表达式,这些正则表达式可能需要几页代码来手动解析。
我建议您查看http://www.regular-expressions.info以获得对正则表达式的良好介绍,以及 Java 的具体示例。
我假设您正在尝试使命令界面尽可能宽容。如果是这种情况,我建议您使用类似于此的算法:
- 读入字符串
- 将字符串拆分为标记
- 使用字典将同义词转换为通用形式
- 例如,将“hit”、“punch”、“strike”和“kick”全部转换为“hit”
- 在无序、包容的基础上执行操作
- 无序——“打猴子的脸”和“打猴子的脸”是一回事
- 包容性- 如果命令应该是“打猴子的脸”并且他们提供“打猴子”,你应该检查有多少命令匹配。如果只有一个命令,请执行此操作。拥有命令优先级甚至可能是一个好主意,即使有匹配项,它也会执行最高操作。
手动解析很有趣……一开始:)
实际上,如果命令不是很复杂,您可以像在命令行解释器中使用的那样对待它们。您可以使用一个库列表:http: //java-source.net/open-source/command-line。我认为您可以从apache commons CLI或args4j(使用注释)开始。它们有据可查,使用起来非常简单。它们会自动处理解析,您唯一需要做的就是读取对象中的特定字段。
如果您有更复杂的命令,那么创建正式语法可能是一个更好的主意。有一个非常好的库,带有图形编辑器、调试器和语法解释器。它被称为ANTLR(和编辑器ANTLRWorks),它是免费的:)还有一些示例语法和教程。
我会看一下Zork的Java 迁移,并倾向于一个简单的自然语言处理器(由标记化或正则表达式驱动),如下所示(来自此链接):
公共静态布尔simpleNLP(字符串输入行,字符串关键字[]) { 诠释我; int maxToken = 关键字.长度; 到,从; 如果(输入线长度()=输入线长度())返回假;// 检查空行和空行 而(到 >=0 ) { to = inputline.indexOf(' ',from); 如果(到 > 0){ lexed.addElement(inputline.substring(from,to)); 从=到; 而(inputline.charAt(来自)=='' && from =keywords.length) { status = true; 休息;} } } 返回状态; }
...
在我的书中,任何让程序员有理由再次关注 Zork 的东西都很好,只要注意 Grues。
...
Sun 本身建议远离 StringTokenizer 并改用 String.spilt 方法。
您还需要查看 Pattern 类。
再次投票给 ANTLR/ANTLRWorks。如果您创建文件的两个版本,一个带有用于实际执行命令的 Java 代码,另一个没有(仅带有语法),那么您就有了该语言的可执行规范,这对于测试非常有用,对文档来说是一个福音,如果您决定移植它,可以节省大量时间。
如果这是为了解析命令行,我建议使用Commons Cli。
Apache Commons CLI 库提供了一个用于处理命令行界面的 API。
试试JavaCC一个 Java 解析器生成器。
它有很多解释语言的特性,并且在 Eclipse 上得到很好的支持。
@CodingTheWheel 继承你的代码,稍微清理一下并通过 eclipse ( ctrl++ shift)f并插入到这里:)
包括每行前面的四个空格。
public static boolean simpleNLP(String inputline, String keywords[]) {
if (inputline.length() < 1)
return false;
List<String> lexed = new ArrayList<String>();
for (String ele : inputline.split(" ")) {
lexed.add(ele);
}
boolean status = false;
to = 0;
for (i = 0; i < lexed.size(); i++) {
String s = (String) lexed.get(i);
if (s.equalsIgnoreCase(keywords[to])) {
to++;
if (to >= keywords.length) {
status = true;
break;
}
}
}
return status;
}
一个简单的空格字符串分词器应该可以工作,但实际上有很多方法可以做到这一点。
下面是一个使用分词器的例子:
String command = "kick person";
StringTokenizer tokens = new StringTokenizer(command);
String action = null;
if (tokens.hasMoreTokens()) {
action = tokens.nextToken();
}
if (action != null) {
doCommand(action, tokens);
}
然后令牌可以进一步用于参数。这一切都假设参数中没有使用空格......所以你可能想要滚动你自己的简单解析机制(比如获取第一个空格并使用之前的文本作为操作,或者如果你不介意使用正则表达式速度命中),只需将其抽象出来,以便可以在任何地方使用。
如果语言很简单,就像
动词名词
然后用手拆分效果很好。
如果它更复杂,您应该真正研究像 ANTLR 或 JavaCC 这样的工具。
我在http://javadude.com/articles/antlrtut有一个关于 ANTLR (v2) 的教程,它将让您了解它是如何工作的。
JCommander看起来相当不错,虽然我还没有测试它。
如果您的文本包含一些分隔符,那么您可以使用您的split
方法。
如果文本包含不规则字符串意味着其中的格式不同,那么您必须使用regular expressions
.
split 方法可以将字符串拆分成指定子字符串表达式的数组regex
。它的参数有两种形式,分别是:split( String regex
)和split( String regex, int limit
),其中split( String regex
)实际上是通过调用split(String regex, int limit)来实现的,limit是0。那么,当limit>0和limit<0分别代表什么?
jdk时解释:当limit >0时子数组的长度达到limit,即如果可能的话,可以将limit-1细分,剩余为一个子串(除了被limit-1次的字符有字符串拆分结束) ;
limit <0表示对数组的长度没有限制;
limit = 0字符串结尾的空字符串将被截断。
StringTokenizer
class 是出于兼容性原因,保留了遗留类,所以我们应该尝试使用 String 类的 split 方法。参考链接