first commit
This commit is contained in:
89
internal/spot/parser.go
Normal file
89
internal/spot/parser.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package spot
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Regex pour les deux formats de spots cluster
|
||||
var (
|
||||
// Format standard : DX de SPOTTER: FREQ DX MODE COMMENT TIME
|
||||
SpotRe = regexp.MustCompile(`(?i)DX\sde\s([\w\d\/]+?)(?:-[#\d-]+)?\s*:\s*(\d+\.\d+)\s+([\w\d\/]+)\s+(?:(CW|SSB|FT8|FT4|RTTY|USB|LSB|FM)\s+)?(.+?)\s+(\d{4}Z)`)
|
||||
|
||||
// Format court : FREQ DX DATE TIME COMMENT <SPOTTER>
|
||||
SpotReShort = regexp.MustCompile(`^(\d+\.\d+)\s+([\w\d\/]+)\s+\d{2}-\w{3}-\d{4}\s+(\d{4}Z)\s+(.+?)\s*<([\w\d\/]+)>\s*$`)
|
||||
|
||||
// Détection rapide du format court
|
||||
ShortSpotDetectRe = regexp.MustCompile(`^\d+\.\d+\s+[\w\d\/]+\s+\d{2}-\w{3}-\d{4}`)
|
||||
)
|
||||
|
||||
// ParseResult contient le spot parsé et une éventuelle erreur
|
||||
type ParseResult struct {
|
||||
Spot *Spot
|
||||
Err error
|
||||
Skipped bool // true si la ligne n'est pas un spot (pas une erreur)
|
||||
}
|
||||
|
||||
// ParseLine tente de parser une ligne brute du cluster en Spot
|
||||
// Retourne nil si la ligne n'est pas un spot DX
|
||||
func ParseLine(line string, clusterName string) *Spot {
|
||||
// Détecter si c'est un spot
|
||||
isSpot := strings.Contains(line, "DX de ") || ShortSpotDetectRe.MatchString(line)
|
||||
if !isSpot {
|
||||
return nil
|
||||
}
|
||||
|
||||
match := SpotRe.FindStringSubmatch(line)
|
||||
if len(match) > 0 {
|
||||
return parseStandardFormat(match, clusterName)
|
||||
}
|
||||
|
||||
match = SpotReShort.FindStringSubmatch(line)
|
||||
if len(match) > 0 {
|
||||
return parseShortFormat(match, clusterName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseStandardFormat(match []string, clusterName string) *Spot {
|
||||
freqKHz := parseFreq(match[2])
|
||||
return &Spot{
|
||||
Spotter: match[1],
|
||||
FrequencyKHz: freqKHz,
|
||||
DX: match[3],
|
||||
Mode: match[4],
|
||||
Comment: strings.TrimSpace(match[5]),
|
||||
Time: match[6],
|
||||
ClusterName: clusterName,
|
||||
Source: SourceCluster,
|
||||
}
|
||||
}
|
||||
|
||||
func parseShortFormat(match []string, clusterName string) *Spot {
|
||||
freqKHz := parseFreq(match[1])
|
||||
return &Spot{
|
||||
FrequencyKHz: freqKHz,
|
||||
DX: match[2],
|
||||
Time: match[3],
|
||||
Comment: strings.TrimSpace(match[4]),
|
||||
Spotter: match[5],
|
||||
ClusterName: clusterName,
|
||||
Source: SourceCluster,
|
||||
}
|
||||
}
|
||||
|
||||
// parseFreq parse une fréquence string en kHz float64
|
||||
// Gère kHz (>1000) et MHz (<1000) automatiquement
|
||||
func parseFreq(s string) float64 {
|
||||
f, err := strconv.ParseFloat(s, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
// Si < 1000 c'est en MHz, on convertit en kHz
|
||||
if f < 1000 {
|
||||
return f * 1000.0
|
||||
}
|
||||
return f
|
||||
}
|
||||
Reference in New Issue
Block a user