簡體   English   中英

用Java Scanner庫解析此問題的最有效方法?

[英]Most efficient way to parse this with the Java Scanner library?

我正在嘗試使用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 +”)拆分它以獲取值,但是我我很好奇我可能還有其他選擇。 :\\

輸入看起來很復雜,足以警告完整的解析器。 我建議使用諸如ANTLR( http://www.antlr.org/ )之類的庫。

我首先用關鍵字定義一個枚舉,例如:

 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;
}

這種方法怎么樣:

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,...

您將必須創建一個Command接口:

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); 
    }
}

(此代碼可能無法編譯)

如果文件很大,我建議您可以使用java.io.RandomAccessFile,它可以跳過要解析的任何區域,而且速度非常快。 如果將整個文件映射到內存中,可能會降低應用程序的速度。

也可以使用java.util.StringTokenizer拆分簡單的大小寫形式,例如,空格,逗號等。 它比正則表達式更快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM