From ddf979e65bd8f7b07f66a077e1862b8a4c8b2755 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 29 Oct 2018 22:58:30 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E5=BC=95=E6=93=8E=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E8=8B=A5=E5=B9=B2=E5=86=85=E7=BD=AE=E5=87=BD=E6=95=B0?= =?UTF-8?q?;gstr=E5=A2=9E=E5=8A=A0=E5=AF=B9=E4=B8=AD=E6=96=87=E6=88=AA?= =?UTF-8?q?=E5=8F=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- g/os/gview/gview.go | 78 ++++++++++++++++--- g/util/gstr/gstr.go | 26 +++++++ geg/os/gview/build_in_funcs/build_in_funcs.go | 27 +++++++ geg/util/gstr/gstr_substr.go | 11 +++ 4 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 geg/os/gview/build_in_funcs/build_in_funcs.go create mode 100644 geg/util/gstr/gstr_substr.go diff --git a/g/os/gview/gview.go b/g/os/gview/gview.go index 3a35879fa..a7e0f9c31 100644 --- a/g/os/gview/gview.go +++ b/g/os/gview/gview.go @@ -8,10 +8,14 @@ package gview import ( + "gitee.com/johng/gf/g/encoding/gurl" + "gitee.com/johng/gf/g/os/gtime" + "gitee.com/johng/gf/g/util/gstr" + "strings" "sync" "bytes" "errors" - "html/template" + "text/template" "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/encoding/ghash" "gitee.com/johng/gf/g/util/gconv" @@ -30,7 +34,7 @@ type View struct { } // 输出到模板页面时保留HTML标签原意,不做自动escape处理 -type HTML = template.HTML +type HTML = string // 模板变量 type Params = map[string]interface{} @@ -79,9 +83,19 @@ func New(path string) *View { } view.SetDelimiters("{{", "}}") // 内置方法 - view.BindFunc("text", view.funcText) - view.BindFunc("html", view.funcHtml) - view.BindFunc("include", view.funcInclude) + view.BindFunc("text", view.funcText) + view.BindFunc("html", view.funcHtmlEncode) + view.BindFunc("htmlencode", view.funcHtmlEncode) + view.BindFunc("htmldecode", view.funcHtmlDecode) + //view.BindFunc("htmlchars", view.funcHtmlChars) + //view.BindFunc("htmldechars", view.funcHtmlCharsDecode) + view.BindFunc("url", view.funcUrlEncode) + view.BindFunc("urlencode", view.funcUrlEncode) + view.BindFunc("urldecode", view.funcUrlDecode) + view.BindFunc("date", view.funcDate) + view.BindFunc("substr", view.funcSubStr) + view.BindFunc("compare", view.funcCompare) + view.BindFunc("include", view.funcInclude) return view } @@ -206,16 +220,16 @@ func (view *View) BindFunc(name string, function interface{}) { } // 模板内置方法:include -func (view *View) funcInclude(file string, data...map[string]interface{}) template.HTML { +func (view *View) funcInclude(file string, data...map[string]interface{}) string { var m map[string]interface{} = nil if len(data) > 0 { m = data[0] } content, err := view.Parse(file, m) if err != nil { - return template.HTML(err.Error()) + return err.Error() } - return template.HTML(content) + return string(content) } // 模板内置方法:text @@ -224,8 +238,52 @@ func (view *View) funcText(html interface{}) string { } // 模板内置方法:html -func (view *View) funcHtml(html interface{}) template.HTML { - return template.HTML(gconv.String(html)) +func (view *View) funcHtmlEncode(html interface{}) string { + return ghtml.Entities(gconv.String(html)) +} + +// 模板内置方法:htmldecode +func (view *View) funcHtmlDecode(html interface{}) string { + return ghtml.EntitiesDecode(gconv.String(html)) +} + +// 模板内置方法:htmlchars +func (view *View) funcHtmlChars(html interface{}) string { + return ghtml.SpecialChars(gconv.String(html)) +} + +// 模板内置方法:htmlcharsdecode +func (view *View) funcHtmlCharsDecode(html interface{}) string { + return ghtml.SpecialCharsDecode(gconv.String(html)) +} + +// 模板内置方法:url +func (view *View) funcUrlEncode(url interface{}) string { + return gurl.Encode(gconv.String(url)) +} + +// 模板内置方法:urldecode +func (view *View) funcUrlDecode(url interface{}) string { + if content, err := gurl.Decode(gconv.String(url)); err == nil { + return content + } else { + return err.Error() + } +} + +// 模板内置方法:date +func (view *View) funcDate(format string, timestamp interface{}) string { + return gtime.NewFromTimeStamp(gconv.Int64(timestamp)).Format(format) +} + +// 模板内置方法:compare +func (view *View) funcCompare(value1, value2 interface{}) int { + return strings.Compare(gconv.String(value1), gconv.String(value2)) +} + +// 模板内置方法:substr +func (view *View) funcSubStr(start, end int, str interface{}) string { + return gstr.SubStr(gconv.String(str), start, end) } diff --git a/g/util/gstr/gstr.go b/g/util/gstr/gstr.go index be1d69b01..eeb46a7da 100644 --- a/g/util/gstr/gstr.go +++ b/g/util/gstr/gstr.go @@ -84,4 +84,30 @@ func IsNumeric(s string) bool { } } return true +} + +// 字符串截取,支持中文 +func SubStr(str string, start int, length...int) (substr string) { + // 将字符串的转换成[]rune + rs := []rune(str) + lth := len(rs) + // 简单的越界判断 + if start < 0 { + start = 0 + } + if start >= lth { + start = lth + } + end := lth + if len(length) > 0 { + end = start + length[0] + if end < start { + end = lth + } + } + if end > lth { + end = lth + } + // 返回子串 + return string(rs[start : end]) } \ No newline at end of file diff --git a/geg/os/gview/build_in_funcs/build_in_funcs.go b/geg/os/gview/build_in_funcs/build_in_funcs.go new file mode 100644 index 000000000..90ea14ca9 --- /dev/null +++ b/geg/os/gview/build_in_funcs/build_in_funcs.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + "gitee.com/johng/gf/g" +) + +func main() { + tplContent := ` +{{"
测试
"|text}} +{{"
测试
"|html}} +{{"<div>测试</div>"|htmldecode}} +{{"https://gfer.me"|url}} +{{"https://gfer.me"|urldecode}} +{{1540822968 | date "Y-m-d"}} +{{"1540822968" | date "Y-m-d H:i:s"}} +{{compare "A" "B"}} +{{compare "1" "2"}} +{{compare 2 1}} +{{compare 1 1}} +{{"我是中国人" | substr 2 -1}} +{{"我是中国人" | substr 2 2}} +` + content, err := g.View().ParseContent(tplContent, nil) + fmt.Println(err) + fmt.Println(string(content)) +} diff --git a/geg/util/gstr/gstr_substr.go b/geg/util/gstr/gstr_substr.go new file mode 100644 index 000000000..db59f4ad7 --- /dev/null +++ b/geg/util/gstr/gstr_substr.go @@ -0,0 +1,11 @@ +package main + +import ( + "fmt" + "gitee.com/johng/gf/g/util/gstr" +) + +func main() { + fmt.Println(gstr.SubStr("我是中国人", 2)) + fmt.Println(gstr.SubStr("我是中国人", 2, 2)) +}