0

我正在尝试使用 Java 的 Scanner 库解析一个大文件的一部分,但我很难确定解析此文本的最佳路径。

SECTOR 199
FLAGS 0x1000
AMBIENT LIGHT 0.67
EXTRA LIGHT 0.00
COLORMAP 0
TINT 0.00 0.00 0.00
BOUNDBOX 7.399998 8.200002 6.199998 9.399998 8.500000 7.099998
COLLIDEBOX 7.605121 8.230770 6.200000 9.399994 8.469233 7.007693
CENTER 8.399998 8.350001 6.649998
RADIUS 1.106797
VERTICES 12
0: 1810
1: 1976
2: 1977
3: 1812
4: 1978
5: 1979
6: 1820
7: 1980
8: 1821
9: 1981
10: 1982
11: 1811
SURFACES 1893 8

它有一些可选字段(SOUND、COLLIDEBOX),所以我不能像处理文件的前一部分那样按特定顺序解析。我不确定如何在不使其效率极低的情况下执行此操作,目前我一直在考虑解析每一行,然后将其与 String.split("\s+") 拆分以获取值,但我我很好奇我还有什么其他选择。:\

4

4 回答 4

2

输入看起来很复杂,足以保证一个成熟的解析器。我建议使用诸如 ANTLR ( http://www.antlr.org/ ) 之类的库。

于 2010-08-17T13:11:55.720 回答
1

我首先使用关键字定义一个枚举,例如:

 public enum Keyword {SECTOR, FLAGS, AMBIENT, EXTRA, COLORMAP, TINT, 
    BOUNDBOX, COLLIDEBOX, CENTER, RADIUS, VERTICES, SURFACES}

解析可以逐行完成,在空白字符处拆分。然后我将第一个元素转换为 Keyword 类中的枚举,并使用一个简单的 switch 构造来处理这些值:

public Model parse(List<String> lines) {

   Model model = new Model();

   Iterator<String> it = lines.iterator();
   while(it.hasNext()) {
      String[] elements = it.next().split("\s+");

      switch(Keyword.valueOf(elements[0])) {
        case SECTOR: model.addSector(elements[1]); break;
        case FLAGS: model.addFlags(elements[1]); break;
        // ...
        case VERTICES:
          int numberOfVertices = Integer.parseInt(elements[1]);
          for (int i = 0; i < numberOfVertices; i++) {
             elements = it.next().split("\s+");
             model.addVertice(i, elements[1]);
          }
          break;
        case default:
          // handle malformed line

      }
   }
   return model;
}
于 2010-08-17T14:04:04.227 回答
1

这种方法怎么样:

find next command (SECTOR, FLAGS, AMBIENT LIGHT, EXTRA LIGHT, etc)
no command found? -> output error and stop
map to command implementation 
execute command (pass it the scanner and your state holder)
command impl handles specific reading of arguments
rinse, repeat,...

您将必须创建一个命令接口:

public interface Command {
    String getName();
    void execute(Scanner in, ReadState state);
}

以及您可能遇到的每种命令的单独实现:

public class SectorCommand implements Command {
    public String getName() {
        return "SECTOR";
    }
    public void execute(Scanner in, ReadState state) {
        state.setSector(in.nextInt());
    }
}

以及某种工厂来查找命令:

public class CommandFactory {

    private Map<String, Command> commands;
    public CommandFactory() {
        commands = new HashMap<String, Command>();
        addCommand(new SectorCommand());
        // add other commands
    }
    public Command findCommand(Scanner in) {
        for (Map.Entry<String, Command> entry : commands.entrySet()) {
            if (in.findInLine(entry.getKey())) {
                return commands.get(entry.getValue);
            }
        }
        throw new IllegalArgumentException("No command found");
    }
    private void addCommand(Command command) {
        commands.put(command.getName(), command); 
    }
}

(此代码可能无法编译)

于 2010-08-17T14:27:06.240 回答
0

如果文件很大,我建议你可以使用 java.io.RandomAccessFile,它可以跳过你想要解析的任何区域,而且速度非常快。如果您将整个文件映射到内存中,它可能会减慢您的应用程序。

也可以使用 java.util.StringTokenizer 来分割简单的大小写。例如,空格、逗号等。它比正则表达式更快。

于 2010-08-17T14:29:50.670 回答