Самый эффективный способ проанализировать это с помощью библиотеки Java Scanner?

Я пытаюсь проанализировать часть большого файла с помощью библиотеки 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+") для получения значений, но я Мне любопытно, какие еще варианты у меня могут быть. :\


person Unrealomega    schedule 17.08.2010    source источник


Ответы (4)


Ввод выглядит достаточно сложным, чтобы гарантировать полноценный синтаксический анализатор. Я бы рекомендовал использовать такую ​​библиотеку, как ANTLR ( http://www.antlr.org/).

person Arne Deutsch    schedule 17.08.2010
comment
Возможно, придется пойти по этому пути, хотя я не знаю, хочу ли я переписать свой код. :\ Уже потратил на это много времени, но спасибо за предложение. :3 - person Unrealomega; 17.08.2010

Сначала я бы определил перечисление с ключевыми словами, например:

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

Разбор может выполняться построчно, разбивая символы на пробелы. Затем я преобразовал бы первый элемент в перечисление из класса Keyword и использовал бы простую конструкцию переключателя для обработки значений:

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;
}
person Andreas Dolk    schedule 17.08.2010
comment
Мне нравится внешний вид этого. Чистый, простой и уже проверяет файлы на наличие искажений. Я могу использовать это сейчас, для целей тестирования. - person Unrealomega; 17.08.2010

Как насчет этого подхода:

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

(этот код может не скомпилироваться)

person Adriaan Koster    schedule 17.08.2010

Если файл очень большой, я предлагаю вам использовать java.io.RandomAccessFile, он может пропустить любую область, которую вы хотите проанализировать, и это очень быстро. Если вы сопоставляете весь файл с памятью, это может замедлить работу вашего приложения.

Альтернативой является использование java.util.StringTokenizer для разделения простого регистра. Например, пробел, запятая и т. д. Это быстрее, чем регулярное выражение.

person Mercy    schedule 17.08.2010