diff --git a/.gitignore b/.gitignore index d865b72..bbe12fd 100644 --- a/.gitignore +++ b/.gitignore @@ -30,4 +30,5 @@ dist/ core/dist .verysync test -.sillyplus \ No newline at end of file +.sillyplus +test* \ No newline at end of file diff --git a/core/node_strings.go b/core/node_strings.go new file mode 100644 index 0000000..c2fa8b4 --- /dev/null +++ b/core/node_strings.go @@ -0,0 +1,161 @@ +package core + +import ( + "bytes" + "fmt" + "net/url" + "regexp" + "strconv" + "strings" +) + +type Strings struct { +} + +func (sender *Strings) Contains(s, substr string) bool { + return strings.Contains(s, substr) +} + +func (sender *Strings) Replace(s string, old string, new string, n int) string { + if n == 0 { + n = -1 + } + return strings.Replace(s, old, new, n) +} + +func (sender *Strings) ReplaceAll(s string, old string, new string) string { + return strings.ReplaceAll(s, old, new) +} + +func (sender *Strings) Split(s string, sep string, n int) []string { + return strings.SplitN(s, sep, n) +} + +func (sender *Strings) EncodeQueryString(params map[string]interface{}) string { + var buf bytes.Buffer + for key, value := range params { + if buf.Len() > 0 { + buf.WriteByte('&') + } + buf.WriteString(url.QueryEscape(key)) + buf.WriteByte('=') + switch v := value.(type) { + case string: + buf.WriteString(url.QueryEscape(v)) + case int: + buf.WriteString(strconv.Itoa(v)) + case int64: + buf.WriteString(strconv.Itoa(int(v))) + case int32: + buf.WriteString(strconv.Itoa(int(v))) + case bool: + buf.WriteString(strconv.FormatBool(v)) + default: + buf.WriteString(url.QueryEscape(fmt.Sprintf("%v", v))) + } + } + return buf.String() +} + +func (sender *Strings) DecodeQueryString(querystring string) map[string]interface{} { + values, err := url.ParseQuery(querystring) + if err != nil { + panic(err) + } + params := make(map[string]interface{}) + for key, values := range values { + if len(values) > 0 { + value := values[0] + if intValue, err := strconv.Atoi(value); err == nil { + params[key] = intValue + } else if boolValue, err := strconv.ParseBool(value); err == nil { + params[key] = boolValue + } else { + params[key] = value + } + } + } + return params +} + +// 将含有 CQ码 的文本解析成文本和 CQ 对象数组 +func (sender *Strings) ParseCQText(text string) []interface{} { + cqRegex := regexp.MustCompile(`\[CQ:(\w+)(.*?)\]`) + cqMatches := cqRegex.FindAllStringSubmatch(text, -1) + result := make([]interface{}, 0, len(cqMatches)*2+1) + // 依次解析 CQ 码和文本 + lastIndex := 0 + for _, match := range cqMatches { + // 添加 CQ 码前的文本 + if matchIndex := strings.Index(text[lastIndex:], match[0]); matchIndex > 0 { + result = append(result, text[lastIndex:lastIndex+matchIndex]) + lastIndex += matchIndex + } + + // 解析 CQ 码 + params := make(map[string]string) + paramRegex := regexp.MustCompile(`(\w+)=([^,]+)`) + paramMatches := paramRegex.FindAllStringSubmatch(match[2], -1) + for _, paramMatch := range paramMatches { + params[paramMatch[1]] = strings.TrimSpace(paramMatch[2]) + } + result = append(result, CQ{ + Type: match[1], + Params: params, + }) + + lastIndex += len(match[0]) + } + + // 添加最后一个 CQ 码后的文本 + if lastIndex < len(text) { + result = append(result, text[lastIndex:]) + } + + return result +} + +// CQ 对象 +type CQ struct { + Type string + Params map[string]string +} + +// 将 CQ 对象数组转换回原始文本 +func (sender *Strings) StringifyCQText(cqList []interface{}) string { + var sb strings.Builder + for _, item := range cqList { + switch item := item.(type) { + case string: + sb.WriteString(item) + case CQ: + sb.WriteString(fmt.Sprintf("[CQ:%s", item.Type)) + for k, v := range item.Params { + sb.WriteString(fmt.Sprintf(",%s=%s", k, v)) + } + sb.WriteString("]") + case map[string]interface{}: + cq := CQ{ + Type: item["Type"].(string), + Params: convertParams(item["Params"].(map[string]interface{})), + } + sb.WriteString(fmt.Sprintf("[CQ:%s", cq.Type)) + for k, v := range cq.Params { + sb.WriteString(fmt.Sprintf(",%s=%s", k, v)) + } + sb.WriteString("]") + } + } + return sb.String() +} + +// 将 map[string]interface{} 类型的 params 转换为 map[string]string 类型 +func convertParams(params map[string]interface{}) map[string]string { + result := make(map[string]string) + for k, v := range params { + if s, ok := v.(string); ok { + result[k] = s + } + } + return result +} diff --git a/core/plugin_impl.go b/core/plugin_impl.go index 887f91a..1fe4dce 100644 --- a/core/plugin_impl.go +++ b/core/plugin_impl.go @@ -1,14 +1,11 @@ package core import ( - "bytes" "encoding/base64" "fmt" "io/ioutil" "net/http" - "net/url" "regexp" - "strconv" "strings" "time" @@ -483,75 +480,6 @@ func (t *TimeJsImpl) Parse(timeStr, layout, locale string) (tt time.Time, err er return tt, nil } -type Strings struct { -} - -func (sender *Strings) Contains(s, substr string) bool { - return strings.Contains(s, substr) -} - -func (sender *Strings) Replace(s string, old string, new string, n int) string { - if n == 0 { - n = -1 - } - return strings.Replace(s, old, new, n) -} - -func (sender *Strings) ReplaceAll(s string, old string, new string) string { - return strings.ReplaceAll(s, old, new) -} - -func (sender *Strings) Split(s string, sep string, n int) []string { - return strings.SplitN(s, sep, n) -} - -func (sender *Strings) EncodeQueryString(params map[string]interface{}) string { - var buf bytes.Buffer - for key, value := range params { - if buf.Len() > 0 { - buf.WriteByte('&') - } - buf.WriteString(url.QueryEscape(key)) - buf.WriteByte('=') - switch v := value.(type) { - case string: - buf.WriteString(url.QueryEscape(v)) - case int: - buf.WriteString(strconv.Itoa(v)) - case int64: - buf.WriteString(strconv.Itoa(int(v))) - case int32: - buf.WriteString(strconv.Itoa(int(v))) - case bool: - buf.WriteString(strconv.FormatBool(v)) - default: - buf.WriteString(url.QueryEscape(fmt.Sprintf("%v", v))) - } - } - return buf.String() -} - -func (sender *Strings) DecodeQueryString(querystring string) map[string]interface{} { - values, err := url.ParseQuery(querystring) - if err != nil { - panic(err) - } - params := make(map[string]interface{}) - for key, values := range values { - if len(values) > 0 { - value := values[0] - if intValue, err := strconv.Atoi(value); err == nil { - params[key] = intValue - } else if boolValue, err := strconv.ParseBool(value); err == nil { - params[key] = boolValue - } else { - params[key] = value - } - } - } - return params -} - type Fmt struct { }