99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package napcat
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// ParseCQ 将 CQ 码字符串解析为消息段数组。
|
|
// 文本与 [CQ:type,k=v] 混排时会还原为对应的段序列。
|
|
func ParseCQ(s string) []Segment {
|
|
var out []Segment
|
|
var text strings.Builder
|
|
flush := func() {
|
|
if text.Len() > 0 {
|
|
out = append(out, Text(unescapeText(text.String())))
|
|
text.Reset()
|
|
}
|
|
}
|
|
for i := 0; i < len(s); {
|
|
if strings.HasPrefix(s[i:], "[CQ:") {
|
|
end := strings.IndexByte(s[i:], ']')
|
|
if end < 0 {
|
|
text.WriteString(s[i:])
|
|
break
|
|
}
|
|
end += i
|
|
flush()
|
|
out = append(out, parseCQBody(s[i+4:end]))
|
|
i = end + 1
|
|
continue
|
|
}
|
|
text.WriteByte(s[i])
|
|
i++
|
|
}
|
|
flush()
|
|
return out
|
|
}
|
|
|
|
func parseCQBody(body string) Segment {
|
|
parts := strings.Split(body, ",")
|
|
seg := Segment{Type: strings.ToLower(strings.TrimSpace(parts[0])), Data: map[string]any{}}
|
|
for _, p := range parts[1:] {
|
|
k, v, ok := strings.Cut(p, "=")
|
|
if !ok {
|
|
continue
|
|
}
|
|
seg.Data[strings.TrimSpace(k)] = unescapeParam(v)
|
|
}
|
|
return seg
|
|
}
|
|
|
|
// EncodeCQ 将消息段数组编码为 CQ 码字符串。
|
|
func EncodeCQ(segs []Segment) string {
|
|
var b strings.Builder
|
|
for _, s := range segs {
|
|
if s.Type == "text" {
|
|
b.WriteString(escapeText(strOf(s.Data["text"])))
|
|
continue
|
|
}
|
|
b.WriteString("[CQ:" + s.Type)
|
|
keys := make([]string, 0, len(s.Data))
|
|
for k := range s.Data {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, k := range keys {
|
|
b.WriteString(",")
|
|
b.WriteString(k)
|
|
b.WriteString("=")
|
|
b.WriteString(escapeParam(strOf(s.Data[k])))
|
|
}
|
|
b.WriteString("]")
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// String 将单个消息段编码为 CQ 码。
|
|
func (s Segment) String() string { return EncodeCQ([]Segment{s}) }
|
|
|
|
func escapeText(s string) string {
|
|
r := strings.NewReplacer("&", "&", "[", "[", "]", "]")
|
|
return r.Replace(s)
|
|
}
|
|
|
|
func escapeParam(s string) string {
|
|
r := strings.NewReplacer("&", "&", "[", "[", "]", "]", ",", ",")
|
|
return r.Replace(s)
|
|
}
|
|
|
|
func unescapeText(s string) string {
|
|
r := strings.NewReplacer("[", "[", "]", "]", "&", "&")
|
|
return r.Replace(s)
|
|
}
|
|
|
|
func unescapeParam(s string) string {
|
|
r := strings.NewReplacer(",", ",", "[", "[", "]", "]", "&", "&")
|
|
return r.Replace(s)
|
|
}
|