java - 拆分 METAR/TAF

标签 java regex

我得到以下输入,我想将其分成四个部分:

-
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

先是 METAR,然后是 TAF,然后是 METAR,然后是 TAF。

输入规则:

  1. 机场代码可以更改,但应始终为 3 或 4 个字母。
  2. METARS 将以机场代码或“SPECI”开头,后跟机场代码 (SPECI KPDX)。
  3. TAF 将以机场代码或“TAF AMD”开头,后跟机场代码 (TAF AMD KPDX)。
  4. 在任何报告中,机场代码后面总是跟有日期时间戳。
  5. 在 TAF 中,日期时间戳总是跟在有效时间之后(例如 0215/0318)。
  6. 报告可能少至 2 份,也可能多于 4 份。
  7. 任何报告都可以只是一行。

我想单独获取每个报告,所以我在下面使用正则表达式 ^(\\w+.*?)(?:^\\b|\\Z)代码:

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() ) );

效果很好,我得到了 4 个结果:

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

我遇到过我的正则表达式失败的情况。有时,TAF 行会运行太长并被换行(我对此无法控制),所以它可能看起来像(注意“TAF AMD PDX”下方的“BKN150”):

-
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

发生这种情况时,我得到 5 个结果:

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

谁能想出一个正则表达式来正确拆分这种奇怪的情况?或者,我可以尝试在输入字符串上运行正则表达式之前删除输入字符串中的问题换行符,但我不知道如何检测它。

最佳答案

您可以从以字母开头的行开始。然后收集至少一行,以五个空格开头(您可以轻松地将该条件放宽到至少一个空白字符或其他字符)。然后转到以单词字符开头的下一行。

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

空格周围的 [] 不是必需的,但为了便于阅读,我喜欢将它们包括在内。如果您只想断言,有一行以任何空格开头,请将 [ ]{5} 替换为 \\s

请注意,您不必使用捕获组。前瞻将确保您在一个新报告或文件末尾后跟的位置结束:

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

这稍微更有效并且稍微清理了以下代码(因为您可以使用完整匹配而不是检索组。

更新:

为了适应单行报告的可能性(通常),更容易的是更改结束条件 ^\\b 以匹配新报告的开头。根据评论中给出的格式描述,您可以使用:

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

这需要一个新报告以“可选 SPECI”-“3 或 4 个字母”-“时间戳”或“可选 TAF AMD”-“3 或 4 个字母”-“时间戳”开头。

关于java - 拆分 METAR/TAF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13202096/

相关文章:

ruby - 转义 TextMate 的 $DIALOG 命令的 Ruby 字符串

java - 程序运行时向 JComboBox 添加项目

java - 如何在Spring Boot中更改ProviderSignInController中的属性signUpUrl

java - 如何以编程方式限制下载速度?

java - 在 Java 中围绕 Y 轴旋转图像?

regex - elasticsearch - 使用涉及空间的正则表达式搜索

正则表达式-匹配整个字符串,除非

java - 如何操作一个类中不同类中的变量?

连续的python正则表达式字母

java - 检测 Java 中的任何组合字符