199 lines
4.0 KiB
Go
199 lines
4.0 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/helmbold/richgo/regexp"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
errIncompatibleTopicPart = errors.New("Incompatible topic part")
|
||
|
|
||
|
rxTopicPart = regexp.MustCompile(`\s*\x02` +
|
||
|
`\s*\x03\s*(?P<prefixColor>[0-9]+)` +
|
||
|
`(?P<prefix>[A-Za-z\s]+):` +
|
||
|
`\s*\x03` +
|
||
|
`\s*(?P<text>.+)` +
|
||
|
`\s*\x02` +
|
||
|
`\s*`)
|
||
|
|
||
|
rxMatch = regexp.MustCompile(`^` +
|
||
|
`(?P<homeTeam>` +
|
||
|
`\w+(?:\s+\w+)*)` +
|
||
|
`\s+(?P<homeScore>\-|\d+):(?P<awayScore>\-|\d+)` +
|
||
|
`\s+(?P<awayTeam>\w+(?:\s+\w+)*)` +
|
||
|
`(` +
|
||
|
`\s+(?P<additional>.+)` +
|
||
|
`)?` +
|
||
|
`$`)
|
||
|
|
||
|
rxAdditionalScoreInfo = regexp.MustCompile(`^` +
|
||
|
`(?P<pre>.*?)\s*` +
|
||
|
`(\[(?:` +
|
||
|
`(?P<penTag>P)\s*(?P<penScore>\d+:\d+)` +
|
||
|
`|` +
|
||
|
`(?P<extraTag>AET)` +
|
||
|
`)\]\s*)?` +
|
||
|
`\((?P<halfScore>\d+:\d+)\)` +
|
||
|
`\s*(?P<post>.*)` +
|
||
|
`$`)
|
||
|
)
|
||
|
|
||
|
type topicPart struct {
|
||
|
PrefixColor string
|
||
|
Prefix string
|
||
|
|
||
|
Text string
|
||
|
Matches []topicMatchInfo
|
||
|
}
|
||
|
|
||
|
func (t *topicPart) HasMatches() bool {
|
||
|
return t.Matches != nil && len(t.Matches) > 0
|
||
|
}
|
||
|
|
||
|
func (t *topicPart) String() string {
|
||
|
retval := fmt.Sprintf("\x02\x03%s%s:\x03 ", t.PrefixColor, t.Prefix)
|
||
|
if t.Matches == nil || len(t.Matches) == 0 {
|
||
|
retval += t.Text
|
||
|
} else {
|
||
|
first := true
|
||
|
for _, match := range t.Matches {
|
||
|
if !first {
|
||
|
retval += " + "
|
||
|
}
|
||
|
retval += match.String()
|
||
|
first = false
|
||
|
}
|
||
|
}
|
||
|
retval += "\x02"
|
||
|
return retval
|
||
|
}
|
||
|
|
||
|
type topicMatchInfo struct {
|
||
|
HomeTeam string
|
||
|
AwayTeam string
|
||
|
Current *topicScoreInfo
|
||
|
Additional string
|
||
|
}
|
||
|
|
||
|
type topicAdditionalScoreInfo struct {
|
||
|
IsAET bool
|
||
|
PenScore string
|
||
|
HalfScore string
|
||
|
|
||
|
Pre string
|
||
|
Post string
|
||
|
}
|
||
|
|
||
|
func (i *topicAdditionalScoreInfo) String() string {
|
||
|
retval := ""
|
||
|
switch {
|
||
|
case len(i.PenScore) > 0:
|
||
|
retval += fmt.Sprintf("[P %s]", i.PenScore)
|
||
|
case i.IsAET:
|
||
|
retval += "[AET]"
|
||
|
}
|
||
|
if len(retval) > 0 {
|
||
|
retval += " "
|
||
|
}
|
||
|
if len(i.HalfScore) > 0 {
|
||
|
retval += fmt.Sprintf("(%s)", i.HalfScore)
|
||
|
}
|
||
|
|
||
|
if len(i.Pre) > 0 {
|
||
|
if len(retval) > 0 {
|
||
|
retval = " " + retval
|
||
|
}
|
||
|
retval = i.Pre + retval
|
||
|
}
|
||
|
|
||
|
if len(i.Post) > 0 {
|
||
|
if len(retval) > 0 {
|
||
|
retval += " "
|
||
|
}
|
||
|
retval += i.Post
|
||
|
}
|
||
|
return retval
|
||
|
}
|
||
|
|
||
|
func (m *topicMatchInfo) AdditionalScoreInfo() *topicAdditionalScoreInfo {
|
||
|
a := rxAdditionalScoreInfo.Match(m.Additional)
|
||
|
if a == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return &topicAdditionalScoreInfo{
|
||
|
HalfScore: a.NamedGroups["halfScore"],
|
||
|
IsAET: len(a.NamedGroups["penScore"]) > 0 || len(a.NamedGroups["extraTag"]) > 0,
|
||
|
PenScore: a.NamedGroups["penScore"],
|
||
|
|
||
|
Pre: a.NamedGroups["pre"],
|
||
|
Post: a.NamedGroups["post"],
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m *topicMatchInfo) String() string {
|
||
|
retval := fmt.Sprintf("%s %s %s", m.HomeTeam, m.Current, m.AwayTeam)
|
||
|
if len(m.Additional) > 0 {
|
||
|
retval += " " + m.Additional
|
||
|
}
|
||
|
return retval
|
||
|
|
||
|
}
|
||
|
|
||
|
type topicScoreInfo struct {
|
||
|
HomeScore int
|
||
|
AwayScore int
|
||
|
}
|
||
|
|
||
|
func (s *topicScoreInfo) String() string {
|
||
|
if s == nil {
|
||
|
return "-:-"
|
||
|
}
|
||
|
return fmt.Sprintf("%d:%d", s.HomeScore, s.AwayScore)
|
||
|
}
|
||
|
|
||
|
func parseTopicPart(s string) (r topicPart, err error) {
|
||
|
match := rxTopicPart.Match(s)
|
||
|
if match == nil {
|
||
|
err = errIncompatibleTopicPart
|
||
|
return
|
||
|
}
|
||
|
r.PrefixColor = match.NamedGroups["prefixColor"]
|
||
|
r.Prefix = match.NamedGroups["prefix"]
|
||
|
r.Text = match.NamedGroups["text"]
|
||
|
|
||
|
// Try to get match info if compatible
|
||
|
matchCompatible := true
|
||
|
matchInfos := []topicMatchInfo{}
|
||
|
for _, matchPart := range strings.Split(r.Text, " + ") {
|
||
|
match = rxMatch.Match(matchPart)
|
||
|
if match == nil {
|
||
|
matchCompatible = false
|
||
|
break
|
||
|
}
|
||
|
matchInfo := topicMatchInfo{}
|
||
|
matchInfo.HomeTeam = match.NamedGroups["homeTeam"]
|
||
|
matchInfo.AwayTeam = match.NamedGroups["awayTeam"]
|
||
|
homeScore, err := strconv.Atoi(match.NamedGroups["homeScore"])
|
||
|
if err == nil {
|
||
|
awayScore, err := strconv.Atoi(match.NamedGroups["awayScore"])
|
||
|
if err == nil {
|
||
|
matchInfo.Current = &topicScoreInfo{
|
||
|
HomeScore: homeScore,
|
||
|
AwayScore: awayScore,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
matchInfo.Additional = match.NamedGroups["additional"]
|
||
|
matchInfos = append(matchInfos, matchInfo)
|
||
|
}
|
||
|
if matchCompatible {
|
||
|
r.Matches = matchInfos
|
||
|
}
|
||
|
return
|
||
|
}
|