90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
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
|
|
}
|