Come scrivere parser multi-formato?

1

Sto per creare un formato di file specifico per un particolare progetto.

Non ci sono metadati speciali relativi al file, poiché possono essere salvati nel database, in un file, ecc. Quindi l'estensione del file, la data, ecc. non hanno alcuna importanza: solo il contenuto lo fa.

Ora so che il formato avrà diverse iterazioni, quindi la prima cosa che sto facendo è progettarla con ulteriori versioni in mente.

Quello che ho pensato è il seguente:

<format-id>       -> 4 bytes
<format-version>  -> 1 byte

Ora la parte difficile: quando voglio analizzare qualsiasi versione del formato, cosa dovrei fare?

Ho pensato di utilizzare un PushbackInputStream , leggere i primi 5 byte e recuperare il parser di versione appropriato sulla base di quei byte, quindi non leggere i byte e presentare il flusso "pristine" al parser effettivo. In questo modo posso testare i parser in modo indipendente senza usare il mio "parser-aggregator".

Esempio:

byte[] identifier = "ABCD".getBytes(UTF_8);
try (PushbackInputStream in = ...) {
  byte[] header = IOUtils.readFully(in, new byte[5]);
  in.unread(header);
  if (!Arrays.equals(identifier, Arrays.copyOf(header, 4))) {
    throw new UnknownFormatException();
  }
  int version = header[4];
  getParser(version).parse(in);
}

Il secondo modo in cui ho pensato è di presentare l'avvio del flusso al parser e lasciarlo accettare o rifiutare di analizzare il resto del flusso:

try (PushbackInputStream in = ...) {
  byte[] header = IOUtils.readFully(in, new byte[5]);
  in.unread(header);
  for (Parser parser: parsers) {
    if (parser.accept(header)) {
      parser.parse(in);
      break;
    }
  }
}

La mia domanda è: esistono solide tecniche per implementare un parser multi-formato? Ad esempio, in che modo% sw_out% di Java Swing gestisce così tanti formati?

Note:

  • Sto principalmente cercando di evitare ogni parser per cercare di analizzare il flusso. Non voglio assolutamente che ciò accada. Questa domanda risponde a questo, ma non è quello che voglio.
posta Olivier Grégoire 11.08.2016 - 15:29
fonte

2 risposte

2

Perché preoccuparsi di ri-analizzare l'intestazione? Nel momento in cui il parser specifico della tua versione è stato istanziato, sai già cosa deve contenere l'intestazione, quindi analizza il corpo.

Se l'intestazione contiene altre informazioni di cui ha bisogno il parser del corpo, basta passarlo come argomento quando si crea un'istanza del parser del corpo.

Puoi pensare a questo come un formato incapsulato [header][body] , in cui l'intestazione ti dice quale parser del corpo usare. Se hai bisogno di più metadati, il corpo può contenere un% co_de nidificato o qualsiasi altro formato necessario.

    
risposta data 10.10.2016 - 18:31
fonte
0

Crea uno stream. Passa ad un parser in miniatura che guarda solo il formato e la versione. Quindi ricrea il flusso e passalo al parser corretto.

In questo modo, non istanzia nessun parser pesante fino a quando non si presenta la necessità.

    
risposta data 11.08.2016 - 16:00
fonte

Leggi altre domande sui tag