Created
December 29, 2013 07:59
-
-
Save hideshi/8168465 to your computer and use it in GitHub Desktop.
This is a parser for SIGMET which is a format for weather information. See also: http://d.hatena.ne.jp/hideshi_o/20130105/1357367954
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract sealed class Bulletin | |
case class SigmetBulletin ( | |
header:Header | |
,firstLine:FirstLine | |
,mainBody:MainBody | |
) extends Bulletin | |
case class Header( | |
identificationMessage:String = "" | |
,icao:String = "" | |
,dateTimeGroup:String = "" | |
,correction:String = "" | |
) extends Bulletin | |
case class FirstLine( | |
icaoLocationIndicatorOfATS:String | |
,messageIdentifier:String | |
,dailySequenceNumber:String | |
,validityIndicator:String | |
,beginAndEndDateTimeGroup:String | |
,icaoLocationIndicatorOfMWO:String | |
) extends Bulletin | |
case class MainBody( | |
firuircta:FIRUIRCTA | |
,phenomenon:String | |
,obsfcst:OBSFCST | |
,locationOfThePhenomenon:String | |
,flightLevelAndExtent:FlightLevel | |
,movement:Movement | |
,expectedChanges:String | |
) extends Bulletin | |
case class FIRUIRCTA ( | |
icao:String | |
,name:String | |
,kind:String | |
) extends Bulletin | |
case class OBSFCST ( | |
observedOrFcst:String | |
,optionalTimeGroup:String = "" | |
) extends Bulletin | |
case class FlightLevel ( | |
indication:String = "" | |
,level:String = "" | |
) extends Bulletin | |
case class Movement ( | |
indication:String = "" | |
,direction:String = "" | |
,speed:String = "" | |
) extends Bulletin | |
import scala.util.parsing.combinator.RegexParsers | |
class SigmetParser extends RegexParsers { | |
def parse(data:String) = parseAll(all, data) | |
def all:Parser[Any] = { | |
opt(header)~firstline~mainBody ^^ { | |
case Some(header)~firstLine~mainBody => | |
SigmetBulletin(header, firstLine, mainBody) | |
case None~firstLine~mainBody => | |
SigmetBulletin(Header(), firstLine, mainBody) | |
} | |
} | |
def header:Parser[Header] = { | |
("(WC|WS|WV)[A-Z]{2}[0-9]{2}".r)~("[A-Z]{4}".r)~("[0-9]{6}".r)~("(CC[AB])?".r) ^^ { | |
case identificationMessage~icao~dateTimeGroup~correction => | |
Header(identificationMessage,icao,dateTimeGroup,correction) | |
} | |
} | |
def firstline:Parser[FirstLine] = { | |
("[A-Z]{4}".r)~"SIGMET"~("(([A-Z]{1,2})?[0-9]?[0-9])".r)~"VALID"~("[0-9]{6}/[0-9]{6}".r)~("[A-Z]{4}-".r) ^^ { | |
case icaoLocationIndicatorOfATS~messageIdentifier~dailySequenceNumber~validityIndicator~beginAndEndDateTimeGroup~icaoLocationIndicatorOfMWO => | |
FirstLine(icaoLocationIndicatorOfATS,messageIdentifier,dailySequenceNumber,validityIndicator,beginAndEndDateTimeGroup,icaoLocationIndicatorOfMWO) | |
} | |
} | |
def mainBody:Parser[MainBody] = { | |
firuircta~phenomenon~obsfcst~location~opt(flightLevel)~opt(movement)~opt(expectedChanges)<~(""".*""".r) ^^ { | |
case firuircta~phenomenon~obsfcst~location~Some(flightLevel)~Some(movement)~Some(expectedChanges) => | |
MainBody(firuircta, phenomenon, obsfcst, location, flightLevel, movement, expectedChanges) | |
case firuircta~phenomenon~obsfcst~location~Some(flightLevel)~None~Some(expectedChanges) => | |
MainBody(firuircta, phenomenon, obsfcst, location, flightLevel, Movement(), expectedChanges) | |
case firuircta~phenomenon~obsfcst~location~Some(flightLevel)~Some(movement)~None => | |
MainBody(firuircta, phenomenon, obsfcst, location, flightLevel, movement, "") | |
case firuircta~phenomenon~obsfcst~location~Some(flightLevel)~None~None => | |
MainBody(firuircta, phenomenon, obsfcst, location, flightLevel, Movement(), "") | |
case firuircta~phenomenon~obsfcst~location~None~Some(movement)~Some(expectedChanges) => | |
MainBody(firuircta, phenomenon, obsfcst, location, FlightLevel(), movement, expectedChanges) | |
case firuircta~phenomenon~obsfcst~location~None~None~Some(expectedChanges) => | |
MainBody(firuircta, phenomenon, obsfcst, location, FlightLevel(), Movement(), expectedChanges) | |
case firuircta~phenomenon~obsfcst~location~None~Some(movement)~None => | |
MainBody(firuircta, phenomenon, obsfcst, location, FlightLevel(), movement, "") | |
case firuircta~phenomenon~obsfcst~location~None~None~None => | |
MainBody(firuircta, phenomenon, obsfcst, location, FlightLevel(), Movement(), "") | |
} | |
} | |
def firuircta:Parser[FIRUIRCTA] = { | |
("""[A-Z]{4}""".r)~("""[A-Z\s]+?(FIR(/UIR)?|UIR|CTA)""".r) ^^ { | |
case icao~name => | |
val xs = name.split("""\s""") | |
FIRUIRCTA(icao, xs.init.reduceLeft{_ + " " + _}, xs.last) | |
} | |
} | |
def phenomenon:Parser[String] = { | |
"""(OBSC|EMBD|FRQ|SQL|SEV|FZRA|HVY|VA CLD|RDOACT CLD)\s?(TSGR|TS|TURB|ICE|MTW)?""".r | |
} | |
def obsfcst:Parser[OBSFCST] = { | |
("""(OBS|FCST)""".r)~opt("""AT [0-9]{4,6}Z""".r) ^^ { | |
case observedOrFcst~Some(optionalTimeGroup) => OBSFCST(observedOrFcst, optionalTimeGroup) | |
case observedOrFcst~None => OBSFCST(observedOrFcst) | |
} | |
} | |
def location:Parser[String] = { | |
rep("""([NSEW]{1,3}\s|(WI(THIN)?\s)?(AREA\s)?([0-9]{2}\s?NM\s)?([NSEW]{1,3}\s)?)?(OF\s)?((LINE|ETNA)\s)?\(?([NSEW][0-9]{2,5}|-|AND)\)?""".r) ^^ { | |
case (xs:List[String]) if !(xs.isEmpty) => | |
println(xs) | |
xs.reduceLeft{_ + " " + _} | |
case _ => "" | |
} | |
} | |
def flightLevel:Parser[FlightLevel] = { | |
("""(TOPS?\s)?(TOPS?\s|ABV\s|BLW\s|SFC\/)?FL[0-9]{3}((\/|-)[0-9]{3})?""".r) ^^ { | |
case flightLevel => | |
val indication = flightLevel.split("FL")(0) + "FL" | |
val level = flightLevel.split("FL")(1) | |
FlightLevel(indication, level) | |
} | |
} | |
def movement:Parser[Movement] = { | |
("""MOV"""~("""[NSEW]{1,3}""".r)~opt("""[0-9]{2}\s?(KMH|KT)""".r) | """STNR""") ^^ { | |
case indication~direction~Some(speed) => Movement(indication.toString, direction.toString, speed.toString) | |
case indication~direction~None => Movement(indication.toString, direction.toString) | |
case indication => Movement(indication.toString) | |
} | |
} | |
def expectedChanges:Parser[String] = { | |
("""(INTSF|WKN|NC)""".r)<~("""\s?=""".r) | |
} | |
} | |
val bulletins = List( | |
"WSTH31 VTBS 121200 CCA VHHK SIGMET 4 VALID 031200/031600 VHHH- VHHK HONG KONG FIR EMBD TS FCST S OF N20 E OF E112 TOP FL360 STNR NC=" | |
,"WSSR20 WSSS 091131 WSJC SIGMET 3 VALID 091140/091540 WSSS- WSJC SINGAPORE FIR EMBD TS OBS AT 1130Z N OF N01 E OF E106 W OF E114 STNR NC=" | |
,"WSNT03 KKCI 032340 KZNY SIGMET C17 VALID 032345/040345 KKCI- KZNY NEW YORK OCEANIC FIR FRQ TS OBS WI AREA N2400 W05500 - N2300 W04930 - N1845 W05645 - N2100 W05800 - N2400 W05500 TOP FL450 MOV E 15KT INTSF=" | |
,"WSVS31 VVGL 122305 VVTS SIGMET 9 VALID 122330/130230 VVGL- VVTS HOCHIMINH FIR EMBD TS OBS S OF LINE N1420 E10930 - N1000 E10400 TOP FL280 MOV W 10KMH WKN=" | |
,"WSUK31 EGGY 121120 EGTT SIGMET 01 VALID 121125/121525 EGRR- EGTT LONDON FIR EMBD TSGR OBS AT 1115Z SE OF LINE N5130 E00200 - N5000 W00400 TOPS FL220 MOV NE 30KT NC=" | |
,"WSAU21 AMMC 280546 YBBB SIGMET BS02 VALID 280600/281000 YMMC- YBBB BRISBANE FIR SEV TURB FCST AT 0600Z WI S3900 E15100 - S4300 E15100 - S4300 E16000 - S4100 E16300 - S3700 E16300 - S3900 E16000 FL260/370 MOV E 20 KT NC=" | |
,"EDUU SIGMET 1 VALID 050200/050400 EDZF- EDUU RHEIN UIR SEV TURB FCST NE OF LINE N5415 E01130 - N5320 E01425 FL245/350 MOV NE NC=" | |
,"EGTT SIGMET 04 VALID 042300/050300 EGRR- EGTT LONDON FIR SEV TURB FCST S OF LINE N5000 W00800 - N5030 W00700 - N2030 W00500 - N4930 W00400 BLW FL060 MOV E 45KT INTSF=" | |
,"EGTT SIGMET 01 VALID 050300/050700 EGRR- EGTT LONDON FIR SEV TURB OBS S OF LINE N4900 W00800 - N5000 W00400 - N5100 W00300 - N5200 W00100 - N5130 E00100 - N5100 E00130 BLW FL060 MOV ENE 45KT NC=" | |
,"EKDK SIGMET 1 VALID 050025/050425 EKMI- EKDK COPENHAGEN FIR SEV TURB FCST AT 0020Z WITHIN 40NM OF LINE N57 E00609 - N5606 E01041 - N5501 E01247 FL240-390 MOV NE 15KT NC=" | |
,"LFFF SIGMET 3 VALID 050100/050400 LFPW- LFFF PARIS FIR/UIR SEV TURB FCST N OF N4930 AND W OF E00000 SFC/FL050 MOV E 30KT INTSF=" | |
,"LFRR SIGMET 1 VALID 050100/050400 LFPW- LFRR BREST FIR/UIR SEV TURB FCST WI N4930 W00415 - N5000 W00200 - N5000 W00015 - N4930 W00015 - N4845 W00400 SFC/FL050 MOV E 30KT INTSF =" | |
,"LIRR SIGMET 01 VALID 050130/050530 LIMM- LIRR ROMA FIR VA CLD OBS AT 040430Z WI 15 NM ESE OF ETNA (N3745 E1500) FL090/130 MOV SE 15 KT=" | |
) | |
val parser = new SigmetParser | |
bulletins.map(b => (b, parser.parse(b)))./*filter(r => r.successful).*/foreach{x => | |
println() | |
println(x._1) | |
println(x._2) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment