1

出于学术目的,我们的重要团队(我和一个朋友)正在用 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(它们都失败了)。

4

1 回答 1

0

要调试这样的问题,请从更简单的正则表达式开始并从那里构建,即尝试匹配

 N=N
 N=N S=C
 ...
 N=N S=C O=C E=N NS=0 NE=0 NO=0 OE=0 SE=0 SO=1

(相应地缩短正则表达式)。这将帮助您确定出现问题的正则表达式中的位置。

也就是说,我建议用这个正则表达式解析配置:

\s*([^\s=]+)\s*=\s*(\S)

将输入分成几行,然后将其重复应用于每一行以读取每个“单词”。

这在 Java 方面付出了更多努力,但它可以检查正则表达式并使您的代码易于阅读、理解和扩展……因为几天后,您将添加另一个图块或新选项——一个一个月后,正则表达式将控制你的生活。

于 2012-05-11T15:13:51.667 回答