2017-07-11 4 views
-1

Ich habe eine Wetterdatei, in der ich den ersten Wert für "air_temp", der in einer JSON-Datei aufgezeichnet wurde, extrahieren möchte. Das Format, das dieser HTTP-Retriever verwendet, ist Regex (ich weiß, dass es nicht die beste Methode ist).Regex Return First Match

ich die JSON-Datei auf 2 Dateneinträge der Einfachheit halber verkürzt haben - es gibt in der Regel 100.

{ 
    "observations": { 
    "notice": [ 
     { 
     "copyright": "Copyright Commonwealth of Australia 2017, Bureau of Meteorology. For more information see: http://www.bom.gov.au/other/copyright.shtml http://www.bom.gov.au/other/disclaimer.shtml", 
     "copyright_url": "http://www.bom.gov.au/other/copyright.shtml", 
     "disclaimer_url": "http://www.bom.gov.au/other/disclaimer.shtml", 
     "feedback_url": "http://www.bom.gov.au/other/feedback" 
     } 
    ], 
    "header": [ 
     { 
     "refresh_message": "Issued at 12:11 pm EST Tuesday 11 July 2017", 
     "ID": "IDN60901", 
     "main_ID": "IDN60902", 
     "name": "Canberra", 
     "state_time_zone": "NSW", 
     "time_zone": "EST", 
     "product_name": "Capital City Observations", 
     "state": "Aust Capital Territory" 
     } 
    ], 
    "data": [ 
     { 
     "sort_order": 0, 
     "wmo": 94926, 
     "name": "Canberra", 
     "history_product": "IDN60903", 
     "local_date_time": "11/12:00pm", 
     "local_date_time_full": "20170711120000", 
     "aifstime_utc": "20170711020000", 
     "lat": -35.3, 
     "lon": 149.2, 
     "apparent_t": 5.7, 
     "cloud": "Mostly clear", 
     "cloud_base_m": 1050, 
     "cloud_oktas": 1, 
     "cloud_type_id": 8, 
     "cloud_type": "Cumulus", 
     "delta_t": 3.6, 
     "gust_kmh": 11, 
     "gust_kt": 6, 
     "air_temp": 9.0, 
     "dewpt": 0.2, 
     "press": 1032.7, 
     "press_qnh": 1031.3, 
     "press_msl": 1032.7, 
     "press_tend": "-", 
     "rain_trace": "0.0", 
     "rel_hum": 54, 
     "sea_state": "-", 
     "swell_dir_worded": "-", 
     "swell_height": null, 
     "swell_period": null, 
     "vis_km": "10", 
     "weather": "-", 
     "wind_dir": "WNW", 
     "wind_spd_kmh": 7, 
     "wind_spd_kt": 4 
     }, 
     { 
     "sort_order": 1, 
     "wmo": 94926, 
     "name": "Canberra", 
     "history_product": "IDN60903", 
     "local_date_time": "11/11:30am", 
     "local_date_time_full": "20170711113000", 
     "aifstime_utc": "20170711013000", 
     "lat": -35.3, 
     "lon": 149.2, 
     "apparent_t": 4.6, 
     "cloud": "Mostly clear", 
     "cloud_base_m": 900, 
     "cloud_oktas": 1, 
     "cloud_type_id": 8, 
     "cloud_type": "Cumulus", 
     "delta_t": 2.9, 
     "gust_kmh": 9, 
     "gust_kt": 5, 
     "air_temp": 7.3, 
     "dewpt": 0.1, 
     "press": 1033.1, 
     "press_qnh": 1031.7, 
     "press_msl": 1033.1, 
     "press_tend": "-", 
     "rain_trace": "0.0", 
     "rel_hum": 60, 
     "sea_state": "-", 
     "swell_dir_worded": "-", 
     "swell_height": null, 
     "swell_period": null, 
     "vis_km": "10", 
     "weather": "-", 
     "wind_dir": "NW", 
     "wind_spd_kmh": 4, 
     "wind_spd_kt": 2 
     } 
    ] 
    } 
} 

Die regulären Ausdruck ich derzeit bin mit: .*air_temp": (\d+).* aber kehrt 9 und 7.3 (Einträge 1 und 2). Könnte jemand vorschlagen, nur den ersten Wert zurückzugeben?

Ich habe versucht, faule Quantifier-Gruppe, aber hatten kein Glück.

+0

In welcher Sprache programmieren Sie? – mickmackusa

Antwort

0

Diese Regex helfen sollte. Aber ich denke, Sie sollten die erste Übereinstimmung mit den Funktionen der von Ihnen verwendeten Programmiersprache erfassen und extrahieren.

.*air_temp": (\d{1,3}\.\d{0,3})[\s\S]*?}, 

Um die Regex besser zu verstehen: at this einen Blick darauf werfen.

aktualisieren

Die obige Lösung funktioniert, wenn Sie nur zwei Dateneinträge haben. Seit mehr als zwei Einträge, sollten wir dieses verwendet haben:

header[\s\S]*?"air_temp": (\d{1,3}\.\d{0,3}) 

Hier passen wir das Wort header zuerst und dann alles in einem nicht-gierigen Weise entsprechen. Danach stimmen wir mit unserem erwarteten Muster überein. So bekommen wir das erste Spiel. Spielen Sie mit ihm hier in regex101.

Um die negativen Zahlen zu erfassen, müssen wir prüfen, ob ein - Zeichen existiert oder nicht. Wir tun dies durch ? was bedeutet "Das Fragezeichen zeigt Null oder ein Vorkommen des vorhergehenden Elements".

So ist die regex wird,

header[\s\S]*?"air_temp": (-?\d{1,3}\.\d{0,3})Demo

Aber die Verwendung von \K ohne global Flag (in einer anderen durch mickmackusa gegebene Antwort) ist effizienter. Um negative Zahlen zu erkennen, ist die modifizierte Version dieser Regex

air_temp": \K-?\d{1,2}\.\d{1,2}demo.

Hier {1,2} bedeutet 1 ~ 2 Vorkommen/s des vorherigen Zeichens.Wir verwenden diese als {min_occurance,max_occurance}

+0

Das funktioniert für positive Zahlen! Aber haben Sie auch einen Vorschlag für negative Werte? I.e. wenn "air_temp" -2 ist? –

+0

@HenryBlue, die Antwort wurde aktualisiert. – arif

0

Ich weiß nicht, welche Sprache Sie verwenden, aber es scheint wie ein Unterschied zwischen der globalen Flagge und nicht mit der globalen Flagge.

Wenn das globale Flag nicht gesetzt ist, wird nur das erste Ergebnis zurückgegeben. Wenn das globale Flag in Ihrer Regex gesetzt ist, wird es durch die Rückgabe aller möglichen Ergebnisse iterieren. Sie können es testen leicht Regex101 verwenden, https://regex101.com/r/x1bwg2/1

Der faule/greediness keine Auswirkungen in Bezug auf die Verwendung/nicht mit dem globalen Flag Sie

0

Wenn \K in Ihrer Codierung Sprache erlaubt ist, verwenden Sie diese: Demo

/air_temp": \K[\d.]+/ (117steps), wird dies bei der Suche Ihrer sehr großen JSON Text sehr leistungsfähig sein.

Wenn kein \K erlaubt ist, können Sie eine Capture-Gruppe verwenden: (Demo)

/air_temp": ([\d.]+)/ wird dies noch mit annehmbarer Geschwindigkeit durch Ihre JSON Text bewegen

Beachten Sie, dass es keine globale Flagge am Ende ist des Patterns, so dass die Regex-Engine nach einer Übereinstimmung die Suche beendet.



Update:

Für "weniger wörtlichen" matches (aber es sollte keine Rolle, ob Ihre Quelle zuverlässig ist), könnten Sie verwenden:

Erweiterte Zeichenklasse - enthalten :

/air_temp": \K[\d.-]+/ #still 117 steps 

oder ändern Sie die negierte Zeichenklasse und passen Sie alles an ist keine , (weil der Wert mit einem Komma endet immer):

/air_temp": \K[^,]+/  #still 117 steps 

Für ein sehr strenges Spiel (wenn Sie nach einem Muster suchen, Sie haben ZERO Vertrauen in den Eingangsdaten bedeutet) ...

Es scheint, dass Ihre Daten nicht über eine Dezimalstelle gehen, temps zwischen 0 und 1 prepend einem 0 vor dem Komma, und ich glaube nicht, dass Sie mit temps in den Hunderten kümmern (rechts ?), so könnten Sie verwenden:

/air_temp": \K-?[1-9]?\d(?:\.\d)?  #200steps 

Erläuterung:

  1. Optional negatives Vorzeichen
  2. Optional Zehner
  3. Erforderlich Einerstelle
  4. Optional Dezimalzahl, die durch eine Ziffer

Accuracy Test Demo

befolgt werden müssen

Real Data Demo

+0

\ K ist erlaubt - danke. Obwohl ich negative Temperaturwerte nicht berücksichtigt habe. Was schlagen Sie vor, dass ich zum Beispiel auch -5 verwende? –

+0

@HenryBlue Ich habe meine Antwort mit ein paar neuen Mustern und Erklärungen aktualisiert.Sie sollten sich einen Moment Zeit nehmen, um Ihre Frage mit Ihren neuen Anforderungen zu aktualisieren, damit unsere Antworten sinnvoll sind. Wenn Sie Fragen haben, fragen Sie einfach. – mickmackusa