From b82b707a255d754fffaabc565dfc8b795f5b0e18 Mon Sep 17 00:00:00 2001 From: windyboy Date: Wed, 24 Dec 2025 17:23:41 +0800 Subject: [PATCH] refactor parser packages --- .../adapter/parser/{ => aviation}/aviation.go | 31 +----- .../aviation_parser_bench_test.go | 3 +- .../{ => aviation}/aviation_parser_test.go | 2 +- .../parser/{ => aviation}/constants.go | 62 ++++++----- internal/adapter/parser/aviation/pattern.go | 99 +++++++++++++++++ .../parser/{ => aviation}/pattern_test.go | 2 +- internal/adapter/parser/aviation/provider.go | 16 +++ internal/adapter/parser/composite_test.go | 4 +- internal/adapter/parser/provider.go | 17 +-- internal/adapter/parser/schedule/constants.go | 38 +++++++ internal/adapter/parser/schedule/extract.go | 24 +++++ .../{pattern.go => schedule/patterns.go} | 101 +----------------- .../adapter/parser/{ => schedule}/schedule.go | 2 +- .../{ => schedule}/schedule_parser_test.go | 2 +- 14 files changed, 227 insertions(+), 176 deletions(-) rename internal/adapter/parser/{ => aviation}/aviation.go (93%) rename internal/adapter/parser/{ => aviation}/aviation_parser_bench_test.go (99%) rename internal/adapter/parser/{ => aviation}/aviation_parser_test.go (99%) rename internal/adapter/parser/{ => aviation}/constants.go (61%) create mode 100644 internal/adapter/parser/aviation/pattern.go rename internal/adapter/parser/{ => aviation}/pattern_test.go (98%) create mode 100644 internal/adapter/parser/aviation/provider.go create mode 100644 internal/adapter/parser/schedule/constants.go create mode 100644 internal/adapter/parser/schedule/extract.go rename internal/adapter/parser/{pattern.go => schedule/patterns.go} (63%) rename internal/adapter/parser/{ => schedule}/schedule.go (99%) rename internal/adapter/parser/{ => schedule}/schedule_parser_test.go (99%) diff --git a/internal/adapter/parser/aviation.go b/internal/adapter/parser/aviation/aviation.go similarity index 93% rename from internal/adapter/parser/aviation.go rename to internal/adapter/parser/aviation/aviation.go index dd95827..7a1a0dd 100644 --- a/internal/adapter/parser/aviation.go +++ b/internal/adapter/parser/aviation/aviation.go @@ -1,4 +1,4 @@ -package parser +package aviation import ( "caatsm/internal/adapter/dto" @@ -14,35 +14,6 @@ import ( "go.uber.org/zap" ) -const ( - SSR = "ssr" - DepartureCode = "dep" - DepartureTime = "dep_time" - ArrivalCode = "arr" - ArrivalTime = "arr_time" - DestinationCode = "dest" - OtherInfo = "other" - - ReferenceData = "reference_data" - CategorySurveillance = "surve" - Indicator = "indicator" - Other = "other" - AircraftID = "aircraft" - Surveillance = "surve" - Speed = "speed" - Level = "level" - Route = "route" - EstimatedTime = "estt" - AlternateAirport = "alter" - PBN = "pbn" - NavigationEquipment = "nav" - EstimatedElapsedTime = "eet" - SELCALCode = "sel" - PerformanceCategory = "per" - RerouteInformation = "rif" - Remarks = "remark" -) - var ( otherPatterns = []*regexp.Regexp{navPattern, remarkPattern, diff --git a/internal/adapter/parser/aviation_parser_bench_test.go b/internal/adapter/parser/aviation/aviation_parser_bench_test.go similarity index 99% rename from internal/adapter/parser/aviation_parser_bench_test.go rename to internal/adapter/parser/aviation/aviation_parser_bench_test.go index 1b91d53..9897d91 100644 --- a/internal/adapter/parser/aviation_parser_bench_test.go +++ b/internal/adapter/parser/aviation/aviation_parser_bench_test.go @@ -1,4 +1,4 @@ -package parser +package aviation import ( "testing" @@ -134,4 +134,3 @@ func BenchmarkParseMixed(b *testing.B) { _, _ = Parse(msg) } } - diff --git a/internal/adapter/parser/aviation_parser_test.go b/internal/adapter/parser/aviation/aviation_parser_test.go similarity index 99% rename from internal/adapter/parser/aviation_parser_test.go rename to internal/adapter/parser/aviation/aviation_parser_test.go index d785b9c..0cb01ed 100644 --- a/internal/adapter/parser/aviation_parser_test.go +++ b/internal/adapter/parser/aviation/aviation_parser_test.go @@ -1,4 +1,4 @@ -package parser +package aviation import ( "caatsm/internal/domain" diff --git a/internal/adapter/parser/constants.go b/internal/adapter/parser/aviation/constants.go similarity index 61% rename from internal/adapter/parser/constants.go rename to internal/adapter/parser/aviation/constants.go index 16fc4cc..86ded79 100644 --- a/internal/adapter/parser/constants.go +++ b/internal/adapter/parser/aviation/constants.go @@ -1,4 +1,4 @@ -package parser +package aviation import "regexp" @@ -15,25 +15,39 @@ const ( CategoryDelay = "DLA" CategoryFlightPlan = "FPL" - CANCELLED = "CNL" - AirportCode = "airport" - Date = "date" - Task = "task" - Index = "idx" FlightNumber = "number" Register = "reg" + + SSR = "ssr" + DepartureCode = "dep" + DepartureTime = "dep_time" + ArrivalCode = "arr" + ArrivalTime = "arr_time" + DestinationCode = "dest" + OtherInfo = "other" + + ReferenceData = "reference_data" + CategorySurveillance = "surve" + Indicator = "indicator" + Other = "other" + AircraftID = "aircraft" + Surveillance = "surve" + Speed = "speed" + Level = "level" + Route = "route" + EstimatedTime = "estt" + AlternateAirport = "alter" + PBN = "pbn" + NavigationEquipment = "nav" + EstimatedElapsedTime = "eet" + SELCALCode = "sel" + PerformanceCategory = "per" + RerouteInformation = "rif" + Remarks = "remark" ) // 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)*)\)$` @@ -43,19 +57,12 @@ const ( // Compiled regular expressions 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) - 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?)+\)$`) + 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?)+\)$`) categoryRegex = regexp.MustCompile(`\((?P[A-Z]+)-`) emptyLineRemove = regexp.MustCompile(`(?m)^\s*$`) @@ -69,5 +76,4 @@ var ( eetPattern = regexp.MustCompile(`(?s)(-?EET\/(?P(?:[A-Z]{4}\d{4}\s*)+))`) performancePattern = regexp.MustCompile(`(?s)-?PER\/(?P\w)`) reroutePattern = regexp.MustCompile(`(?m)RIF\/(?P.*)[A-Z]{3}\/`) - cancelledPattern = regexp.MustCompile(`\bCNL\b`) ) diff --git a/internal/adapter/parser/aviation/pattern.go b/internal/adapter/parser/aviation/pattern.go new file mode 100644 index 0000000..bc4f1eb --- /dev/null +++ b/internal/adapter/parser/aviation/pattern.go @@ -0,0 +1,99 @@ +package aviation + +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 +} + +var ( + bodyPatterns = map[string]BodyConfig{} +) + +func init() { + // Initialize body patterns. + bodyPatterns = map[string]BodyConfig{ + "ARR": { + Patterns: []PatternConfig{ + { + Pattern: ArrPatternString, + Comments: "Pattern for ARR message", + Expression: ArrPatternExpression, + }, + }, + }, + "DEP": { + Patterns: []PatternConfig{ + { + Pattern: DepPatternString, + Comments: "Pattern for DEP message", + Expression: DepPatternExpression, + }, + }, + }, + "FPL": { + Patterns: []PatternConfig{ + { + Pattern: FplPatternString, + Comments: "Pattern for FPL message", + Expression: FplPatternExpression, + }, + }, + }, + "CNL": { + Patterns: []PatternConfig{ + { + Pattern: CnlPatternString, + Comments: "Pattern for CNL message", + Expression: CnlPatternExpression, + }, + }, + }, + "DLA": { + Patterns: []PatternConfig{ + { + Pattern: DlaPatternString, + Comments: "Pattern for DLA message", + Expression: DlaPatternExpression, + }, + }, + }, + } +} + +// FindPatterns finds the matching body configuration based on the message body. +func FindPatterns(messageBody string) *BodyConfig { + if match := BodyTypePattern.FindStringSubmatch(messageBody); len(match) > 1 { + name := match[1] + 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 { + if matches := pattern.Expression.FindStringSubmatch(messageBody); matches != nil { + result := make(map[string]string) + for i, name := range pattern.Expression.SubexpNames() { + if i != 0 && name != "" { + result[name] = matches[i] + } + } + return result + } + } + } + return nil +} diff --git a/internal/adapter/parser/pattern_test.go b/internal/adapter/parser/aviation/pattern_test.go similarity index 98% rename from internal/adapter/parser/pattern_test.go rename to internal/adapter/parser/aviation/pattern_test.go index e52b9bb..e57feae 100644 --- a/internal/adapter/parser/pattern_test.go +++ b/internal/adapter/parser/aviation/pattern_test.go @@ -1,4 +1,4 @@ -package parser +package aviation import ( . "github.com/onsi/ginkgo/v2" diff --git a/internal/adapter/parser/aviation/provider.go b/internal/adapter/parser/aviation/provider.go new file mode 100644 index 0000000..5990e19 --- /dev/null +++ b/internal/adapter/parser/aviation/provider.go @@ -0,0 +1,16 @@ +package aviation + +import "caatsm/internal/adapter/dto" + +// AviationParser implements the Parser interface for aviation telegrams. +type AviationParser struct{} + +// NewParser creates a new aviation parser instance. +func NewParser() *AviationParser { + return &AviationParser{} +} + +// Parse parses a raw message string and returns a ParsedTelegram. +func (p *AviationParser) Parse(rawText string) (*dto.ParsedTelegram, error) { + return Parse(rawText) +} diff --git a/internal/adapter/parser/composite_test.go b/internal/adapter/parser/composite_test.go index 3c84c71..a8ef50e 100644 --- a/internal/adapter/parser/composite_test.go +++ b/internal/adapter/parser/composite_test.go @@ -2,6 +2,7 @@ package parser import ( "caatsm/internal/adapter/dto" + "caatsm/internal/adapter/parser/aviation" weatherparser "caatsm/internal/adapter/parser/weather" "caatsm/internal/port" @@ -15,7 +16,7 @@ var _ = Describe("CompositeParser", func() { var weatherParser port.WeatherParser BeforeEach(func() { - aviationParser = &AviationParser{} + aviationParser = aviation.NewParser() weatherParser = weatherparser.NewWeatherParser() composite = NewCompositeParser(aviationParser, weatherParser) }) @@ -77,4 +78,3 @@ NNNN` }) }) }) - diff --git a/internal/adapter/parser/provider.go b/internal/adapter/parser/provider.go index c0017ae..d9303b2 100644 --- a/internal/adapter/parser/provider.go +++ b/internal/adapter/parser/provider.go @@ -1,21 +1,12 @@ package parser import ( - "caatsm/internal/adapter/dto" + "caatsm/internal/adapter/parser/aviation" "caatsm/internal/port" ) -// AviationParser implements the Parser interface -type AviationParser struct{} - -// Parse parses a raw message string and returns a ParsedTelegram -func (p *AviationParser) Parse(rawText string) (*dto.ParsedTelegram, error) { - return Parse(rawText) -} - -// ProvideParser creates a composite parser instance that combines weather and aviation parsers +// ProvideParser creates a composite parser instance that combines weather and aviation parsers. func ProvideParser(weatherParser port.WeatherParser) Parser { - aviation := &AviationParser{} - return NewCompositeParser(aviation, weatherParser) + aviationParser := aviation.NewParser() + return NewCompositeParser(aviationParser, weatherParser) } - diff --git a/internal/adapter/parser/schedule/constants.go b/internal/adapter/parser/schedule/constants.go new file mode 100644 index 0000000..23a132e --- /dev/null +++ b/internal/adapter/parser/schedule/constants.go @@ -0,0 +1,38 @@ +package schedule + +import "regexp" + +// String constants +const ( + AirportCode = "airport" + Date = "date" + Task = "task" + Index = "idx" + FlightNumber = "number" + Register = "reg" + ArrivalTime = "arr_time" + DepartureTime = "dep_time" +) + +// 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})$` +) + +// Compiled regular expressions +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) + cancelledPattern = regexp.MustCompile(`\bCNL\b`) +) diff --git a/internal/adapter/parser/schedule/extract.go b/internal/adapter/parser/schedule/extract.go new file mode 100644 index 0000000..a5fa566 --- /dev/null +++ b/internal/adapter/parser/schedule/extract.go @@ -0,0 +1,24 @@ +package schedule + +import ( + "regexp" + "strings" +) + +func extract(data string, exp *regexp.Regexp) map[string]string { + match := exp.FindStringSubmatch(data) + if len(match) > 0 { + return extractData(match, exp) + } + return nil +} + +func extractData(match []string, re *regexp.Regexp) map[string]string { + data := make(map[string]string) + for i, name := range re.SubexpNames() { + if i != 0 && name != "" { + data[name] = strings.TrimSpace(match[i]) + } + } + return data +} diff --git a/internal/adapter/parser/pattern.go b/internal/adapter/parser/schedule/patterns.go similarity index 63% rename from internal/adapter/parser/pattern.go rename to internal/adapter/parser/schedule/patterns.go index 028de80..3c9e216 100644 --- a/internal/adapter/parser/pattern.go +++ b/internal/adapter/parser/schedule/patterns.go @@ -1,20 +1,6 @@ -package parser +package schedule -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 -} +import "regexp" // LineParser represents a line parser configuration. type LineParser struct { @@ -25,61 +11,11 @@ type LineParser struct { } var ( - bodyPatterns = map[string]BodyConfig{} - parserMap = map[string]*regexp.Regexp{} - parserDef = &[]LineParser{} + parserMap = map[string]*regexp.Regexp{} + parserDef = &[]LineParser{} ) func init() { - // Initialize body patterns. - bodyPatterns = map[string]BodyConfig{ - "ARR": { - Patterns: []PatternConfig{ - { - Pattern: ArrPatternString, - Comments: "Pattern for ARR message", - Expression: ArrPatternExpression, - }, - }, - }, - "DEP": { - Patterns: []PatternConfig{ - { - Pattern: DepPatternString, - Comments: "Pattern for DEP message", - Expression: DepPatternExpression, - }, - }, - }, - "FPL": { - Patterns: []PatternConfig{ - { - Pattern: FplPatternString, - Comments: "Pattern for FPL message", - Expression: FplPatternExpression, - }, - }, - }, - "CNL": { - Patterns: []PatternConfig{ - { - Pattern: CnlPatternString, - Comments: "Pattern for CNL message", - Expression: CnlPatternExpression, - }, - }, - }, - "DLA": { - Patterns: []PatternConfig{ - { - Pattern: DlaPatternString, - Comments: "Pattern for DLA message", - Expression: DlaPatternExpression, - }, - }, - }, - } - // Initialize parser map. parserMap = map[string]*regexp.Regexp{ Index: IndexExpression, @@ -296,32 +232,3 @@ func init() { }, } } - -// FindPatterns finds the matching body configuration based on the message body. -func FindPatterns(messageBody string) *BodyConfig { - if match := BodyTypePattern.FindStringSubmatch(messageBody); len(match) > 1 { - name := match[1] - 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 { - if matches := pattern.Expression.FindStringSubmatch(messageBody); matches != nil { - result := make(map[string]string) - for i, name := range pattern.Expression.SubexpNames() { - if i != 0 && name != "" { - result[name] = matches[i] - } - } - return result - } - } - } - return nil -} diff --git a/internal/adapter/parser/schedule.go b/internal/adapter/parser/schedule/schedule.go similarity index 99% rename from internal/adapter/parser/schedule.go rename to internal/adapter/parser/schedule/schedule.go index 3cb496a..a319745 100644 --- a/internal/adapter/parser/schedule.go +++ b/internal/adapter/parser/schedule/schedule.go @@ -1,4 +1,4 @@ -package parser +package schedule import ( "caatsm/internal/domain" diff --git a/internal/adapter/parser/schedule_parser_test.go b/internal/adapter/parser/schedule/schedule_parser_test.go similarity index 99% rename from internal/adapter/parser/schedule_parser_test.go rename to internal/adapter/parser/schedule/schedule_parser_test.go index 8c64b68..e278319 100644 --- a/internal/adapter/parser/schedule_parser_test.go +++ b/internal/adapter/parser/schedule/schedule_parser_test.go @@ -1,4 +1,4 @@ -package parser +package schedule import ( "strings"