diff --git a/internal/parsers/pattern.go b/internal/parsers/pattern.go index d1f5cfc..288ac93 100644 --- a/internal/parsers/pattern.go +++ b/internal/parsers/pattern.go @@ -4,121 +4,350 @@ import ( "regexp" ) +// BodyConfig represents the configuration for parsing message bodies. type BodyConfig struct { Patterns []PatternConfig } +// PatternConfig represents the configuration for a specific pattern. type PatternConfig struct { Pattern string Comments string Expression *regexp.Regexp } +// LineParser represents a line parser configuration. +type LineParser struct { + Airlines []string + MinLen int + WaypointStart int + Fields map[int]string +} + +// Constants for specific values. const ( - arrPatternString = `^\((?P[A-Z]{3})` + - `-(?P[A-Z0-9]+)(\/?(?P[A-Z0-9]+))?` + - `-(?P[A-Z]{4})` + - `-(?P[A-Z]{4})(?P\d{4})\)$` + CANCELLED = "CNL" + AirportCode = "airport" + Date = "date" + Task = "task" + // Index = "idx" +) - // depPatternString represents the regular expression pattern used to match departure patterns. - // The pattern matches strings in the format: "(TYPE-NUMBER-SSR-DEPARTURE-DEPARTURE_TIME-ARRIVAL)". - // The pattern captures the following named groups: - // - category: the three-letter category code - // - number: the alphanumeric flight number - // - ssr: the alphanumeric SSR code - // - departure: the four-letter departure airport code - // - departure_time: the four-digit departure time - // - arrival: the four-letter arrival airport code - depPatternString = `^\((?P[A-Z]{3})-(?P[A-Z0-9]+)(\/(?P[A-Z0-9]+))?-(?P[A-Z]{4})(?P\d{4})-(?P[A-Z]{4})\)$` - - // fplPatternString represents the regular expression pattern used to match flight plan patterns. - // The pattern matches strings in the format: "(CATEGORY-NUMBER-INDICATOR-AIRCRAFT-SURVE-DEPARTURE-DEPARTURE_TIME-SPEED-LEVEL-ROUTE-DESTINATION-ESTT-ALTER-OTHER)". - // The pattern captures the following named groups: - // - category: the three-letter category code - // - number: the alphanumeric flight number - // - indicator: the two-letter indicator - // - aircraft: the alphanumeric aircraft type, optionally followed by a slash and an uppercase letter - // - surve: any character sequence (surveillance information) - // - departure: the four-letter departure airport code - // - departure_time: the four-digit departure time - // - speed: one or more uppercase letters followed by one or more digits (e.g., N123) - // - level: one or more alphanumeric characters (e.g., FL350) - // - route: one or more characters (including newline) representing the flight route - // - destination: the four-letter destination airport code - // - estt: the four-digit estimated time of arrival - // - alter: one or more sequences of a whitespace character followed by exactly four uppercase letters - // - other: any other relevant information, starting with three uppercase letters followed by a forward slash and zero or more characters (including newline) - - fplPatternString = `\((?P[A-Z]{3})-(?P[A-Z]+\d+)-(?P[A-Z]{2})\n-(?P[A-Z]+\d+\/?[A-Z]?)\n?-(?P.*)\n?-(?P[A-Z]{4})(?P\d{4})\n?-(?P[A-Z]+\d+)(?P[A-Z0-9]+)\s+(?P(.|\n)+)\n-(?P[A-Z]{4})(?P\d{4})\s?(?P(\s[A-Z]{4})+)\n?-([A-Z]{3}\/(?:[A-Z]{4}\d{4}\s?)+)?(?P(?m)[A-Z]{3}\/(.|\n)*)\)$` - - cnlPatternString = `^\((?P[A-Z]{3})-(?P\w+\d+)-?(?P[A-Z]{4})?-?(?[A-Z]{4})\)$` - - dlaPatternString = `^\((?P[A-Z]{3})-(?P\w+\d+)-?(?P[A-Z]{4})(?P\d{4})?-?(?[A-Z]{4})(?\d{4})?\)$` +// Regular expression patterns. +const ( + AllDigitsPattern = `^(?P\d+)$` + IndexPattern = `^(?P\(?L?[0-9]+\)?:?\.?)$` + DatePattern = `^(?P\d{2}\w{3})$` + TaskPattern = `(?P[A-Z]\/[A-Z])$` + WaypointPattern = `^(SI:)?(?P\d{4}(\(\d{2}[A-Z]{3}\))?)?\/?(?P[A-Z]{3})\/?(?P\d{4}(\(\d{2}[A-Z]{3}\))?)?$` + FlightNumberPattern = `^(?P[0-9A-Z][0-9A-Z]\d{3,5}(\/\d+)*)$` + RegisterPattern = `^(?PB\d{4})$` + ArrPatternString = `^\((?P[A-Z]{3})-(?P[A-Z0-9]+)(\/?(?P[A-Z0-9]+))?-(?P[A-Z]{4})-(?P[A-Z]{4})(?P\d{4})\)$` + DepPatternString = `^\((?P[A-Z]{3})-(?P[A-Z0-9]+)(\/(?P[A-Z0-9]+))?-(?P[A-Z]{4})(?P\d{4})-(?P[A-Z]{4})\)$` + FplPatternString = `\((?P[A-Z]{3})-(?P[A-Z]+\d+)-(?P[A-Z]{2})\n-(?P[A-Z]+\d+\/?[A-Z]?)\n?-(?P.*)\n?-(?P[A-Z]{4})(?P\d{4})\n?-(?P[A-Z]+\d+)(?P[A-Z0-9]+)\s+(?P(.|\n)+)\n-(?P[A-Z]{4})(?P\d{4})\s?(?P(\s[A-Z]{4})+)\n?-([A-Z]{3}\/(?:[A-Z]{4}\d{4}\s?)+)?(?P(?m)[A-Z]{3}\/(.|\n)*)\)$` + CnlPatternString = `^\((?P[A-Z]{3})-(?P\w+\d+)-?(?P[A-Z]{4})?-?(?[A-Z]{4})\)$` + DlaPatternString = `^\((?P[A-Z]{3})-(?P\w+\d+)-?(?P[A-Z]{4})(?P\d{4})?-?(?[A-Z]{4})(?\d{4})?\)$` ) var ( - bodyTypePattern = regexp.MustCompile(`^\(([A-Z]{3})(.*\n?)+\)$`) + // Pre-compiled regular expressions. + AllDigitsExpression = regexp.MustCompile(AllDigitsPattern) + IndexExpression = regexp.MustCompile(IndexPattern) + TaskExpression = regexp.MustCompile(TaskPattern) + DateExpression = regexp.MustCompile(DatePattern) + WaypointExpression = regexp.MustCompile(WaypointPattern) + FlightNumberExpression = regexp.MustCompile(FlightNumberPattern) + RegisterExpression = regexp.MustCompile(RegisterPattern) + ArrPatternExpression = regexp.MustCompile(ArrPatternString) + DepPatternExpression = regexp.MustCompile(DepPatternString) + FplPatternExpression = regexp.MustCompile(FplPatternString) + CnlPatternExpression = regexp.MustCompile(CnlPatternString) + DlaPatternExpression = regexp.MustCompile(DlaPatternString) + BodyTypePattern = regexp.MustCompile(`^\(([A-Z]{3})(.*\n?)+\)$`) + bodyPatterns = map[string]BodyConfig{} + parserMap = map[string]*regexp.Regexp{} + parserDef = &[]LineParser{} +) +func init() { + // Initialize body patterns. bodyPatterns = map[string]BodyConfig{ "ARR": { Patterns: []PatternConfig{ { - Pattern: arrPatternString, + Pattern: ArrPatternString, Comments: "Pattern for ARR message", - Expression: regexp.MustCompile(arrPatternString), + Expression: ArrPatternExpression, }, }, }, "DEP": { Patterns: []PatternConfig{ { - Pattern: depPatternString, + Pattern: DepPatternString, Comments: "Pattern for DEP message", - Expression: regexp.MustCompile(depPatternString), + Expression: DepPatternExpression, }, }, }, "FPL": { Patterns: []PatternConfig{ { - Pattern: fplPatternString, + Pattern: FplPatternString, Comments: "Pattern for FPL message", - Expression: regexp.MustCompile(fplPatternString), + Expression: FplPatternExpression, }, }, }, "CNL": { Patterns: []PatternConfig{ { - Pattern: cnlPatternString, + Pattern: CnlPatternString, Comments: "Pattern for CNL message", - Expression: regexp.MustCompile(cnlPatternString), + Expression: CnlPatternExpression, }, }, }, "DLA": { Patterns: []PatternConfig{ { - Pattern: dlaPatternString, + Pattern: DlaPatternString, Comments: "Pattern for DLA message", - Expression: regexp.MustCompile(dlaPatternString), + Expression: DlaPatternExpression, }, }, }, } -) + // Initialize parser map. + parserMap = map[string]*regexp.Regexp{ + Index: IndexExpression, + Task: TaskExpression, + Date: DateExpression, + FlightNumber: FlightNumberExpression, + Register: RegisterExpression, + } + + // Initialize parser definitions. + parserDef = &[]LineParser{ + { + Airlines: []string{"FM"}, + MinLen: 6, + WaypointStart: 5, + Fields: map[int]string{ + 0: Task, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"MF"}, + MinLen: 5, + WaypointStart: 4, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"8X"}, + MinLen: 9, + WaypointStart: 7, + Fields: map[int]string{ + 0: Index, + 1: Date, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"HU"}, + MinLen: 6, + WaypointStart: 5, + Fields: map[int]string{ + 0: Index, + 1: Task, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"JD"}, + MinLen: 7, + WaypointStart: 5, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"GS"}, + MinLen: 4, + WaypointStart: 3, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"Y8"}, + MinLen: 6, + WaypointStart: 3, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"3U"}, + MinLen: 8, + WaypointStart: 6, + Fields: map[int]string{ + 0: Index, + 1: Date, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"CK"}, + MinLen: 4, + WaypointStart: 3, + Fields: map[int]string{ + 0: Task, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"G5"}, + MinLen: 8, + WaypointStart: 5, + Fields: map[int]string{ + 0: Index, + 1: Task, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"9C"}, + MinLen: 8, + WaypointStart: 6, + Fields: map[int]string{ + 0: Date, + 1: Task, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"ZH"}, + MinLen: 9, + WaypointStart: 7, + Fields: map[int]string{ + 0: Index, + 1: Task, + 2: Date, + 3: FlightNumber, + 4: Register, + }, + }, + { + Airlines: []string{"8L"}, + MinLen: 6, + WaypointStart: 4, + Fields: map[int]string{ + 0: Index, + 1: Task, + 2: FlightNumber, + 3: Register, + }, + }, + { + Airlines: []string{"SC"}, + MinLen: 9, + WaypointStart: 7, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"PN"}, + MinLen: 7, + WaypointStart: 5, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"CZ"}, + MinLen: 6, + WaypointStart: 4, + Fields: map[int]string{ + 0: Index, + 1: FlightNumber, + 2: Register, + }, + }, + { + Airlines: []string{"HO"}, + MinLen: 7, + WaypointStart: 6, + Fields: map[int]string{ + 0: Index, + 1: Date, + 2: Task, + 3: FlightNumber, + 4: Register, + }, + }, + { + Airlines: []string{"NS"}, + MinLen: 7, + WaypointStart: 6, + Fields: map[int]string{ + 0: Index, + 1: Date, + 2: Task, + 3: FlightNumber, + 4: Register, + }, + }, + { + Airlines: []string{"EU"}, + MinLen: 7, + WaypointStart: 6, + Fields: map[int]string{ + 0: Task, + 1: Date, + 2: FlightNumber, + 3: Register, + }, + }, + } +} + +// FindPatterns finds the matching body configuration based on the message body. func FindPatterns(messageBody string) *BodyConfig { - if match := bodyTypePattern.FindStringSubmatch(messageBody); len(match) > 1 { + if match := BodyTypePattern.FindStringSubmatch(messageBody); len(match) > 1 { name := match[1] - patters := bodyPatterns - if bodyConfig, found := patters[name]; found { + if bodyConfig, found := bodyPatterns[name]; found { return &bodyConfig } } return nil } +// ParseBody parses the message body and returns the extracted values. func ParseBody(messageBody string) map[string]string { if body := FindPatterns(messageBody); body != nil { for _, pattern := range body.Patterns { diff --git a/internal/parsers/schedule_def.go b/internal/parsers/schedule_def.go deleted file mode 100644 index b091746..0000000 --- a/internal/parsers/schedule_def.go +++ /dev/null @@ -1,340 +0,0 @@ -package parsers - -import "regexp" - -const ( - CANCELLED = "CNL" - AirportCode = "airport" - Date = "date" - Task = "task" - // Index = "idx" - AllDigitsPattern = `^(?P\d+)$` - IndexPattern = `^(?P\(?L?[0-9]+\)?:?\.?)$` - DatePattern = `^(?P\d{2}\w{3})$` - // CK task: 01)H/Z - TaskPattern = `(?P[A-Z]\/[A-Z])$` - WaypointPattern = `^(SI:)?(?P\d{4}(\(\d{2}[A-Z]{3}\))?)?\/?(?P[A-Z]{3})\/?(?P\d{4}(\(\d{2}[A-Z]{3}\))?)?$` - FlightNumberPattern = `^(?P[0-9A-Z][0-9A-Z]\d{3,5}(\/\d+)*)$` - RegisterPattern = `^(?PB\d{4})$` -) - -var ( - AllDigitsExpression = regexp.MustCompile(AllDigitsPattern) - - IndexExpression = regexp.MustCompile(IndexPattern) - TaskExpression = regexp.MustCompile(TaskPattern) - DateExpression = regexp.MustCompile(DatePattern) - WaypointExpression = regexp.MustCompile(WaypointPattern) - FlightNumberExpression = regexp.MustCompile(FlightNumberPattern) - RegisterExpression = regexp.MustCompile(RegisterPattern) - - parserMap = map[string]*regexp.Regexp{ - Index: IndexExpression, - Task: TaskExpression, - Date: DateExpression, - FlightNumber: FlightNumberExpression, - Register: RegisterExpression, - } - - parserDef = &[]LineParser{ - { - /** - * 上航(FM)解析 - * 解析参考 - * W/Z FM9134 B2688 1/1ILS (00) TSN0100 SHA - * W/Z FM9133 B2688 1/1ILS (00) SHA0340 TSN - */ - Airlines: []string{"FM"}, - MinLen: 6, - WaypointStart: 5, - Fields: map[int]string{ - 0: Task, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 解析厦航(MF)计划 - * 01) MF8193 B5595 ILS(8) HGH1100 1305TSN - * 02) MF8194 B5595 ILS(8) TSN1355 1550HGH - */ - Airlines: []string{"MF"}, - MinLen: 5, - WaypointStart: 4, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 解析奥凯(8X)计划 - * 计划参考: - *L1: 29OCT BK2735 B2863 ILS IS (3/6) TSN2350(28OCT) HAK - *L2: 29OCT BK2735 B2863 ILS IS (3/6) HAK0435 NKG - */ - Airlines: []string{"8X"}, - MinLen: 9, - WaypointStart: 7, - Fields: map[int]string{ - 0: Index, - 1: Date, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 解析海航(HU)计划 - * 计划参考 - *L04 W/Z HU7204 B5637 (9) SZX/0500 TSN - *L05 W/Z HU7205 B5406 (9) TSN/2355(30OCT) PVG - *1) JD5195 B6727 ILS I(9) SYX/0800 1135/TSN - * - *L07 W/Z GS6571 B3155 (7) XIY/0025 TSN/0245 CGQ - */ - Airlines: []string{"HU"}, - MinLen: 6, - WaypointStart: 5, - Fields: map[int]string{ - 0: Index, - 1: Task, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 1) JD5195 B6727 ILS I(9) SYX/0800 1135/TSN - */ - Airlines: []string{"JD"}, - MinLen: 7, - WaypointStart: 5, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 01 GS7635 B3193 XIY0020(16APR) CGD - */ - Airlines: []string{"GS"}, - MinLen: 4, - WaypointStart: 3, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 杨子快运(Y8) - *01 Y87969 B2119 XMN 1540 HGH - *13 Y87444 B2578 ICN 0235 TSN - */ - Airlines: []string{"Y8"}, - MinLen: 6, - WaypointStart: 3, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 四川航空 (3U) - * 01) 31OCT 3U8863 B6598 CAT1 (10) CKG0010 0235TSN - */ - Airlines: []string{"3U"}, - MinLen: 8, - WaypointStart: 6, - Fields: map[int]string{ - 0: Index, - 1: Date, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 中国货运 (CK) - *01)H/Z CK261 B2076 PVG1535(30OCT) 1705TPE - */ - Airlines: []string{"CK"}, - MinLen: 4, - WaypointStart: 3, - Fields: map[int]string{ - 0: Task, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 华夏航空 (G5) - *L01 W/Z G52665 B7762 (6) CKG/0725 CIH/0940 TSN - */ - Airlines: []string{"G5"}, - MinLen: 8, - WaypointStart: 5, - Fields: map[int]string{ - 0: Index, - 1: Task, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 春秋航空 (9C) - *31OCT W/Z 9C8884 B6573 ILS1/1 (06) TSN0650 SYX - */ - Airlines: []string{"9C"}, - MinLen: 8, - WaypointStart: 6, - Fields: map[int]string{ - 0: Date, - 1: Task, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 深圳航空 (ZH) - *204) W/Z 31OCT ZH9783 B5670 CAT1 (10) SZX0045 0355TSN - */ - Airlines: []string{"ZH"}, - MinLen: 9, - WaypointStart: 7, - Fields: map[int]string{ - 0: Index, - 1: Task, - 2: Date, - 3: FlightNumber, - 4: Register, - }, - }, - { - /** - * 翔鹏航空 (8L) - *L59 W/Z 8L9976 B6959 TSN/0510 CTU/0855 KMG - */ - Airlines: []string{"8L"}, - MinLen: 6, - WaypointStart: 4, - Fields: map[int]string{ - 0: Index, - 1: Task, - 2: FlightNumber, - 3: Register, - }, - }, - { - /** - * 山东航空 (SC) - *(1) SC4717 B3080 CRJ7 ILS I (6) TAO/2350 TSN - */ - Airlines: []string{"SC"}, - MinLen: 9, - WaypointStart: 7, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 西部航空 (PN) - *21) PN6237 B6763 ILS I(9) CKG/0000 0220/TSN - *23) PN6235 B6763 ILS I(9) CKG/0905 1025/WUH/1100 1225/WNZ - */ - Airlines: []string{"PN"}, - MinLen: 7, - WaypointStart: 5, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 南方航空 (CZ) - * - *83. CZ3301/2 B2823 B752 CAN0135 TSN0535 CAN - *02. CZ6973/4 B5239 B737 YIN0235 URC0425 PVG0940 URC1545 YIN - */ - Airlines: []string{"CZ"}, - MinLen: 6, - WaypointStart: 4, - Fields: map[int]string{ - 0: Index, - 1: FlightNumber, - 2: Register, - }, - }, - { - /** - * 吉祥航空 (HO) - * 124) 14NOV W/Z HO1245 B6966 ILS(8) SHA0005 0255CKG - * 125) 14NOV W/Z HO1246 B6966 ILS(8) CKG0340 0630SHA - */ - Airlines: []string{"HO"}, - MinLen: 7, - WaypointStart: 6, - Fields: map[int]string{ - 0: Index, - 1: Date, - 2: Task, - 3: FlightNumber, - 4: Register, - }, - }, - { - /** - * 河北航空 (NS) - * 05) 14NOV N/M NS3230 B3188 ILS(2) TSN2200 2240SJW - */ - Airlines: []string{"NS"}, - MinLen: 7, - WaypointStart: 6, - Fields: map[int]string{ - 0: Index, - 1: Date, - 2: Task, - 3: FlightNumber, - 4: Register, - }, - }, - { - /** - * 成都航空 (EU) - * 38)W/Z 27NOV EU2748 B6900 CAT1 (8) TSN0800 1055CTU - */ - Airlines: []string{"EU"}, - MinLen: 7, - WaypointStart: 6, - Fields: map[int]string{ - 0: Task, - 1: Date, - 2: FlightNumber, - 3: Register, - }, - }, - } -) - -type LineParser struct { - Airlines []string - MinLen int - WaypointStart int - Fields map[int]string -}