package html import ( "bytes" "fmt" "github.com/dlclark/regexp2" "github.com/fthvgb1/wp-go/helper/slice" strings2 "github.com/fthvgb1/wp-go/helper/strings" "html/template" "regexp" "strings" ) var entitlesMap = map[int][]string{ EntCompat: {"&", """, "<", ">"}, EntQuotes: {"&", """, "'", "<", ">"}, EntNoQuotes: {"&", "<", ">"}, EntSpace: {" "}, } var unEntitlesMap = map[int][]string{ EntCompat: {"&", "\"", "<", ">"}, EntQuotes: {"&", "\"", "'", "<", ">"}, EntNoQuotes: {"&", "<", ">"}, EntSpace: {" "}, } const ( EntCompat = 1 EntQuotes = 2 EntNoQuotes = 4 EntSpace = 8 ) func SpecialChars(text string, flag ...int) string { if len(text) < 1 { return "" } flags := EntQuotes if len(flag) > 0 { flags = flag[0] } r, ok := unEntitlesMap[flags] e := entitlesMap[flags] if !ok { r = unEntitlesMap[EntCompat] e = entitlesMap[EntCompat] } if flags&EntSpace == EntSpace { r = append(r, unEntitlesMap[EntSpace]...) e = append(e, entitlesMap[EntSpace]...) } for i, entitle := range r { text = strings.Replace(text, entitle, e[i], -1) } return text } func SpecialCharsDecode(text string, flag ...int) string { flags := EntQuotes if len(flag) > 0 { flags = flag[0] } r, ok := entitlesMap[flags] u := unEntitlesMap[flags] if !ok { r = entitlesMap[EntCompat] u = unEntitlesMap[EntCompat] } if flags&EntSpace == EntSpace { r = append(r, entitlesMap[EntSpace]...) u = append(u, unEntitlesMap[EntSpace]...) } for i, entitle := range r { text = strings.Replace(text, entitle, u[i], -1) } return text } var allHtmlTag = regexp.MustCompile("") func StripTags(str, allowable string) string { html := "" if allowable == "" { return allHtmlTag.ReplaceAllString(str, "") } r := strings.Split(allowable, ">") re := "" for _, reg := range r { if reg == "" { continue } tag := strings.TrimLeft(reg, "<") ree := fmt.Sprintf(`%s|\/%s`, tag, tag) re = fmt.Sprintf("%s|%s", re, ree) } ree := strings.Trim(re, "|") reg := fmt.Sprintf("<(?!%s).*?>", ree) compile, err := regexp2.Compile(reg, regexp2.IgnoreCase) if err != nil { return str } html, err = compile.Replace(str, "", 0, -1) if err != nil { return str } return html } var tag = regexp.MustCompile(`(?is:<(.*?)>)`) //使用忽略大小写和包含换行符模式 func StripTagsX(str, allowable string) string { if allowable == "" { return allHtmlTag.ReplaceAllString(str, "") } tags := tag.ReplaceAllString(allowable, "$1|") or := strings.TrimRight(tags, "|") reg := fmt.Sprintf(`<(/?(%s).*?)>`, or) regx := fmt.Sprintf(`\{\[(/?(%s).*?)\]\}`, or) cp, err := regexp.Compile(reg) if err != nil { return str } rep := cp.ReplaceAllString(str, "{[$1]}") tmp := tag.ReplaceAllString(rep, "") rex, err := regexp.Compile(regx) if err != nil { return str } html := rex.ReplaceAllString(tmp, "<$1>") return html } var selfCloseTags = map[string]string{"area": "", "base": "", "basefont": "", "br": "", "col": "", "command": "", "fecolormatrix": "", "embed": "", "frame": "", "hr": "", "img": "", "input": "", "isindex": "", "link": "", "fecomposite": "", "fefuncr": "", "fefuncg": "", "fefuncb": "", "fefunca": "", "meta": "", "param": "", "!doctype": "", "source": "", "track": "", "wbr": ""} func CloseTag(str string) string { tags := tag.FindAllString(str, -1) if len(tags) < 1 { return str } var tagss = make([]string, 0, len(tags)) for _, s := range tags { ss := strings.Split(s, " ") sss := strings2.Replace(ss[0], map[string]string{ "\\": "", "\n": "", "\\/": "/", }) if strings.Contains(sss, "' { sss = fmt.Sprintf("%s>", sss) } if _, ok := selfCloseTags[strings.Trim(strings.ToLower(sss), "\\/<>")]; ok { continue } tagss = append(tagss, sss) } r := slice.Map(slice.Reverse(UnClosedTag(tagss)), func(s string) string { return fmt.Sprintf("", strings.Trim(s, "<>")) }) return strings.Join(r, "") } func UnClosedTag(s []string) []string { i := 0 for { if len(s[i:]) < 2 { return s } l := s[i] r := fmt.Sprintf(``, strings.Trim(l, "<>")) if s[i+1] == r { if len(s[i+1:]) > 1 { ss := s[:i] s = append(ss, s[i+2:]...) } else { s = s[:i] } i = 0 continue } i++ } } func RenderedHtml(t *template.Template, data map[string]any) (r string, err error) { var buf bytes.Buffer err = t.Execute(&buf, data) if err != nil { return } r = buf.String() return } func BuildOptions[T any, K comparable](a []T, selected K, fn func(T) (K, any, string)) string { s := strings2.NewBuilder() for _, t := range a { k, v, attr := fn(t) ss := "" if k == selected { ss = "selected" } s.Sprintf(``, ss, attr, v, k) } return s.String() }