java拆分MetaR/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
这是一个梅塔,然后是塔夫,然后是梅塔,然后是塔夫
输入规则:
- 机场代码可以更改,但应始终为3或4个字母李>
- METARS将以机场代码或“SPECI”开头,后跟机场代码(SPECI KPDX)李>
- TAFs将以机场代码或“TAF AMD”开头,后跟机场代码(TAF AMD KPDX)李>
- 在任何报告中,机场代码后面都会有日期戳李>
- 在TAF中,日期时间戳后面总是跟着有效时间(例如0215/0318)李>
- 可能只有2份报告,也可能超过4份李>
- 任何报告都可能只是一行李>
我想单独获取每个报告,所以我在以下代码中使用regex ^(\\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
有人能想出一个正则表达式来正确地拆分这个奇怪的案例吗?或者,在运行正则表达式之前,我可以尝试删除输入字符串中的问题换行符,但我不知道如何检测它
# 1 楼答案
你可以用以字母开头的一行开头。然后收集至少一行,以五个空格开头(你可以很容易地将该条件放宽为至少一个空格字符或其他内容)。然后一直到下一行以单词字符开头
空间周围的
[]
是不必要的,但为了可读性,我喜欢包含它们。如果您只想断言有一行以任何空格开头,请将[ ]{5}
替换为\\s
请注意,您不必使用捕获组。前瞻将确保您在一个位置结束,该位置后面是一个新报告或文件的结尾:
这会稍微更高效,并稍微清理以下代码(因为您可以使用完全匹配,而不是检索组)
更新:
为了适应单行报告的可能性(一般来说),更改结束条件
^\\b
以匹配新报告的开头更容易。根据评论中给出的格式说明,您可以使用:这要求新报告以“可选规格”-“3或4个字母”-“时间戳”或“可选TAF AMD”-“3或4个字母”-“时间戳”开头