2012-11-02 13 views
5

ricevo il seguente input che voglio dividere in quattro parti:Splitting out METARs/TAF

- 
KPDX 021453Z 16004KT 10SM FEW007 SCT060 BKN200 11/09 A3002 RMK 
    AO2 SLP166 T01060094 55008 
TAF AMD KPDX 021453Z 0215/0312 10005KT P6SM FEW006 SCT060 BKN150 
    FM021800 11005KT P6SM SCT050 OVC100 
    FM022200 11007KT P6SM -RA OVC050 
    FM030500 12005KT P6SM -RA OVC035 
KSEA 021453Z 15003KT 10SM FEW035 BKN180 11/09 A3001 RMK AO2 
    SLP168 60000 T01110089 58010 
TAF AMD KSEA 021501Z 0215/0318 14004KT P6SM SCT020 BKN150 
    FM021800 16005KT P6SM SCT025 OVC090 
    FM030100 19005KT P6SM OVC070 
    FM030200 15005KT P6SM -RA OVC045 
    FM030600 16007KT P6SM -RA BKN025 OVC045 

E 'un METAR, poi un TAF, poi un METAR, poi un TAF.

regole di ingresso:

  1. I codici aeroportuali possono cambiare, ma dovrebbero essere sempre 3 o 4 lettere.
  2. METARS inizierà con il codice dell'aeroporto, o "SPECI" seguito dal codice dell'aeroporto (SPECI KPDX).
  3. I TAF inizieranno con il codice dell'aeroporto o "TAF AMD" seguito dal codice dell'aeroporto (TAF AMD KPDX).
  4. In qualsiasi rapporto, il codice dell'aeroporto sarà sempre seguito dal timbro datetime.
  5. In un TAF, il timbro datetime sarà sempre seguito dai tempi validi (0215/0318 per esempio).
  6. Ci possono essere solo 2 report, o molti più di 4.
  7. Qualsiasi rapporto potrebbe essere solo una singola riga.

Voglio afferrare ogni rapporto da solo, quindi sto usando la regex ^(\\w+.*?)(?:^\\b|\\Z) nel codice seguente:

ArrayList<String> reports = new ArrayList<String>(); 
Pattern pattern = Pattern.compile("^(\\w+.*?)(?:^\\b|\\Z)", Pattern.DOTALL|Pattern.MULTILINE); 
Matcher matcher = pattern.matcher(input); 
while(matcher.find()) 
    reports.add(new String(matcher.group(1).trim())); 

E le grandi opere, ottengo 4 risultati:

1:

KPDX 021453Z 16004KT 10SM FEW007 SCT060 BKN200 11/09 A3002 RMK 
    AO2 SLP166 T01060094 55008 

2:

TAF AMD KPDX 021453Z 0215/0312 10005KT P6SM FEW006 SCT060 BKN150 
    FM021800 11005KT P6SM SCT050 OVC100 
    FM022200 11007KT P6SM -RA OVC050 
    FM030500 12005KT P6SM -RA OVC035 

3:

KSEA 021453Z 15003KT 10SM FEW035 BKN180 11/09 A3001 RMK AO2 
    SLP168 60000 T01110089 58010 

4:

TAF AMD KSEA 021501Z 0215/0318 14004KT P6SM SCT020 BKN150 
    FM021800 16005KT P6SM SCT025 OVC090 
    FM030100 19005KT P6SM OVC070 
    FM030200 15005KT P6SM -RA OVC045 
    FM030600 16007KT P6SM -RA BKN025 OVC045 

ho incontrato un caso in cui il mio regex fallisce.Di tanto in tanto, una linea TAF verrà eseguito troppo a lungo e verrà avvolto (non ho alcun controllo su questo), quindi potrebbe sembrare (notare la "BKN150" diritto di seguito "TAF AMD PDX"):

- 
KPDX 021453Z 16004KT 10SM FEW007 SCT060 BKN200 11/09 A3002 RMK 
    AO2 SLP166 T01060094 55008 
TAF AMD KPDX 021453Z 0215/0312 10005KT P6SM FEW006 SCT060 
BKN150 
    FM021800 11005KT P6SM SCT050 OVC100 
    FM022200 11007KT P6SM -RA OVC050 
    FM030500 12005KT P6SM -RA OVC035 
KSEA 021453Z 15003KT 10SM FEW035 BKN180 11/09 A3001 RMK AO2 
    SLP168 60000 T01110089 58010 
TAF AMD KSEA 021501Z 0215/0318 14004KT P6SM SCT020 BKN150 
    FM021800 16005KT P6SM SCT025 OVC090 
    FM030100 19005KT P6SM OVC070 
    FM030200 15005KT P6SM -RA OVC045 
    FM030600 16007KT P6SM -RA BKN025 OVC045 

Quando questo accade, ottengo 5 risultati:

1:

KPDX 021453Z 16004KT 10SM FEW007 SCT060 BKN200 11/09 A3002 RMK 
    AO2 SLP166 T01060094 55008 

2:

TAF AMD KPDX 021453Z 0215/0312 10005KT P6SM FEW006 SCT060 

3:

BKN150 
    FM021800 11005KT P6SM SCT050 OVC100 
    FM022200 11007KT P6SM -RA OVC050 
    FM030500 12005KT P6SM -RA OVC035 

4:

KSEA 021453Z 15003KT 10SM FEW035 BKN180 11/09 A3001 RMK AO2 
    SLP168 60000 T01110089 58010 

5:

TAF AMD KSEA 021501Z 0215/0318 14004KT P6SM SCT020 BKN150 
    FM021800 16005KT P6SM SCT025 OVC090 
    FM030100 19005KT P6SM OVC070 
    FM030200 15005KT P6SM -RA OVC045 
    FM030600 16007KT P6SM -RA BKN025 OVC045 

Chiunque può capire una regex che correttamente dividere questo caso strano? In alternativa, potrei provare a rimuovere l'interruzione di riga del problema nella stringa di input prima di eseguire la regex su di esso, ma non riesco a capire come rilevarla.

risposta

2

Si può iniziare con una riga che inizia con una lettera. Quindi raccogli almeno una linea, che inizia con cinque spazi (potresti facilmente allentare quella condizione per almeno un carattere di spazio bianco o qualcosa del genere). E poi vai fino alla riga successiva che inizia con un carattere di parola.

"^(\\w+.*?^[ ]{5}.*?)(?:^\\b|\\Z)" 

Il [] attorno allo spazio non sono necessari, ma mi piace di includerli per migliorare la leggibilità. Se vuoi solo affermare che esiste una riga che inizia con qualsiasi spazio bianco, sostituisci [ ]{5} per \\s.

Si noti che non è necessario utilizzare il gruppo di acquisizione. Un lookahead farà in modo che si finisce in una posizione che è seguito sia da un nuovo rapporto o la fine del file:

"^\\w+.*?^[ ]{5}.*?(?=^\\b|\\Z)" 

Questo è leggermente più efficiente e pulisce il seguente codice un po '(perché è possibile utilizzare la piena corrispondenza invece di recuperare il gruppo

Aggiornamento:.

per accogliere la possibilità di rapporti linea singola (e in generale) è ancora più facile, per cambiare la condizione finale ^\\b per abbinare il inizio di una nuova relazione Secondo il formato descri ption data nel commento, è possibile utilizzare:

"^\\w+.*?(?=^(?:SPECI\\s|TAF\\sAMD\\s)?[A-Z]{3,4}\\s\\d+Z|\\Z)" 

Ciò richiede un nuovo rapporto di iniziare con uno "SPECI optional" - "3 o 4 lettere" - "timestamp" o "opzionale TAF AMD" - "3 o 4 lettere "-" timestamp ".

+0

Questo funziona, tranne che c'è un altro caso possibile che ho dimenticato di menzionare. Ognuno dei report potrebbe essere una sola riga e la soluzione non funzionerà in quell'istanza. Modificherò la mia domanda per includere questa possibilità. – Ralgha

+0

Quindi come si possono distinguere i report a riga singola da quelli racchiusi (sintatticamente)? –

+0

Le regole di formattazione sono coerenti, un METAR inizia sempre con il codice di aeroporto o il codice aeroportuale "SPECI", seguito dal timbro di data/ora.Allo stesso modo i TAF iniziano sempre con il codice aeroportuale o il codice aeroportuale "TAF AMD", seguito dal timbro data/ora. Il timestamp nel TAF sarà sempre seguito dai tempi validi (0215/0318 per esempio). – Ralgha