正则表达式返回第一场比赛

时间:2017-07-11 03:47:10

标签: json regex capture-group

我有一个天气文件,我想在其中提取JSON文件中记录的“air_temp”的第一个值。这个HTTP检索器使用的格式是regex(我知道它不是最好的方法)。

为简单起见,我已将JSON文件缩短为2个数据条目 - 通常为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
      }
    ]
  }
}

我目前使用的正则表达式是:.*air_temp": (\d+).*但这将返回97.3(条目1和2)。有人可以建议只返回第一个值的方法吗?

我尝试过使用懒惰量词组,但没有运气。

3 个答案:

答案 0 :(得分:0)

我不知道你使用的是哪种语言,但它似乎是全局标志与不使用全局标志之间的区别。

如果未设置全局标志,则仅返回第一个结果。如果在正则表达式上设置了全局标志,它将迭代返回所有可能的结果。您可以使用Regex101 https://regex101.com/r/x1bwg2/1

轻松测试

懒惰/贪婪对使用/不使用全局标志不应有任何影响

答案 1 :(得分:0)

这个正则表达式会帮助你。但我认为你应该使用你正在使用的编程语言的功能捕获并提取第一个匹配项。

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

更好地了解正则表达式:看看at this

<强>更新

如果您只有两个数据条目,则上述解决方案有效。对于两个以上的条目,我们应该使用这个:

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

这里我们首先匹配单词header,然后以非贪婪的方式匹配任何内容。在那之后,我们匹配我们的预期模式。因此我们得到了第一场比赛。在regex101中播放。

要捕获负数,我们需要检查是否存在任何-个字符。我们通过?执行此操作,这意味着&#39;问号表示前一个元素出现零次或一次。

所以正则表达式变成了,

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

但是\K没有global标志(在mickmackusa给出的另一个答案中)的使用效率更高。要检测负数,该正则表达式的修改版本是

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

这里{1,2}表示前一个字符的1~2次出现。我们将其用作{min_occurance,max_occurance}

答案 2 :(得分:0)

如果您的编码语言允许使用\K,请使用:Demo

/air_temp": \K[\d.]+/ 117steps )这对搜索非常大的JSON文本非常有效。

如果不允许\K,您可以使用捕获组:(Demo

/air_temp": ([\d.]+)/这仍将通过您的JSON文本以适当的速度移动

请注意,模式末尾没有全局标志,因此在一次匹配后,正则表达式引擎会停止搜索。

更新

对于&#34;较少文字&#34;匹配(但如果您的来源可靠则不重要),您可以使用:

包含-的扩展字符类:

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

或更改为否定字符类并匹配不是,的所有内容(因为值始终以逗号结尾):

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

对于非常严格的匹配(如果您正在寻找一种模式,这意味着您对输入数据有零置信度)......

您的数据似乎不超过一位小数,01之间的温度在小数点前加0,我不会认为你需要担心成百上千的临时工(对吗?),所以你可以使用:

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

说明:

  1. 可选的否定号
  2. 可选十位数
  3. 必填数字
  4. 可选小数,后面必须跟一个数字
  5. Accuracy Test Demo

    Real Data Demo