出于学术目的,我们的重要团队(我和一个朋友)正在用 Java 编写基于图块的游戏。为了玩这些瓷砖,我们得到了一个配置文件,其中包含甲板中所有瓷砖的字符串表示,每行一次。这里有些例子:
N=N S=C O=C E=N NS=0 NE=0 NO=0 OE=0 SE=0 SO=1
N=S S=S O=S E=S NS=0 NE=0 NO=0 OE=0 SE=0 SO=0
在上述表示中,N、S、O 和 E 映射到北、南、东和西的基点,而前四个分配的右侧成员映射到道路 (S)、城市 (C) 和田野 (N) . 以下六组表示两点之间是否存在联系。例如,SO=1 表示南和西是相连的。
我们的第一个想法是使用标准 Java 库提供的 Pattern 类,用正则表达式解析这些行。我的队友编写了一个代码来为整个字符串生成一个模式,组装更小的模式来指示一些枚举的可能值(以前的位置包含基点,资产类型包含道路或城市等结构)。我不会粘贴生成的代码,因为它非常占用空间并且不是很优雅。但是,我可以承认它是正确的。
在继续之前,我想指出实际上是由两个主要部分组成的 tile 字符串:边界规范(即前 4 个分配)和链接规范(最后六个)。因此,我们有两个解析器。第一个能够解析像“N=NS=CO=CE=N”这样的字符串,第二个能够解析“NS=0 NE=0 NO=0 OE=0 SE=0 SO=1”。他们的模式是正确的。我们对它们进行了彻底的测试,所有测试都顺利通过。
现在问题来了。由于平铺字符串总是由第一部分和第二部分组成,我们为整个字符串创建了模式,只需附加第一个和第二个的模式,用 \s+ 分隔它们并围绕它们中的每一个带括号。结果表达式如下:
(N\s*\=\s*(N|S|C)(,(R|B|V|G|N))?\s+S\s*\=\s*(N|S|C)(,(R|B|V|G|N))?\s+O\s*\=\s*(N|S|C)(,(R|B|V|G|N))?\s+E\s*\=\s*(N|S|C)(,(R|B|V|G|N))?)\s+(NS\s*\=\s*(0|1)\s+NE\s*\=\s*(0|1)\s+NO\s*\=\s*(0|1)\s+OE\s*\=\s*(0|1)\s+SE\s*\=\s*(0|1)\s+SO\s*\=\s*(0|1))
我知道,它看起来很糟糕,但它是编译时的结果。然而,我们针对一些字符串进行了测试,就像我在上面发布的那样,只是发现它不会匹配,尽管单个模式匹配。我们试图在一个在线模拟器上运行它,就像这样,它完美匹配。我们不知道如何使它匹配。有任何想法吗?
一些代码:
public Tile from(String tileString) {
Matcher matcher = pattern.matcher(tileString);
return new InnerTile(
tileBorderBuilder.from(matcher.group(1)),
tileLinkageBuilder.from(matcher.group(14)));
}
tileBorderBuilder.from 解析第一部分并返回一个 TileBorder 对象。tileLinkageBuilder.from 做同样的事情并返回一个 TileLinkage 对象。它引发异常:“未找到匹配项”。
PS:我们使用的是 Java SE 1.6 或 Open-JDK6(它们都失败了)。