napcat: NapCatQQ (OneBot 11) Go SDK, initial release
This commit is contained in:
98
cqcode.go
Normal file
98
cqcode.go
Normal file
@ -0,0 +1,98 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user