正则表达式 Return 第一场比赛

Regex Return First Match

我有一个天气文件,我想从中提取记录在 JSON 文件中的 "air_temp" 的第一个值。这个 HTTP 检索器使用的格式是正则表达式(我知道这不是最好的方法)。

为简单起见,我已将 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+).* 但这是 returning 97.3(条目 1 和 2)。有人可以建议只 return 第一个值的方法吗?

我试过使用惰性量词组,但没有成功。

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

如果没有设置全局标志,则只返回第一个结果。如果在您的正则表达式上设置了全局标志,它将遍历返回所有可能的结果。您可以使用 Regex101 轻松测试它,https://regex101.com/r/x1bwg2/1

lazy/greediness 不应该对 using/not 使用全局标志有任何影响

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

.*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.

中使用它

要捕获负数,我们需要检查是否存在 - 个字符。我们通过 ? 来做到这一点,这意味着 'The question mark indicates zero or one occurrence of the preceding element'.

所以正则表达式变成了,

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

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

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

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

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

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

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

/air_temp": ([\d.]+)/ 这仍然会以相当快的速度通过您的 JSON 文本

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



更新:

对于 "less literal" 匹配(但如果您的来源可靠则无关紧要),您可以使用:

扩展字符 class 以包含 -:

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

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

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

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

看来你的数据没有超过小数点后一位,01 之间的温度在小数点前加了一个 0,我不认为你需要担心数百个临时工(对吗?),因此您可以使用:

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

解释:

  1. 可选负号
  2. 可选十位
  3. 需要个位数
  4. 可选的小数点,后面必须跟一个数字

Accuracy Test Demo

Real Data Demo