在golang中,有没有办法在html模板中截断文本?
例如,我的模板中有以下内容:
{{ range .SomeContent }}
....
{{ .Content }}
....
{{ end }
{{ .Content }}
产生:Interdum et malesuada fames ac ante ipsum primis in faucibus。 Aliquam tempus sem ipsum,vel accumsan felis vulputate id。 Donec ultricies sem purus,non aliquam orci dignissim et。整数mi arcu。 Pellentesque a ipsum quis velit venenatis vulputate vulputate ut enim。
我想将其减少到25个字符。
答案 0 :(得分:31)
您可以在模板中使用printf
,模板充当fmt.Sprintf
。在您的情况下,截断字符串将非常简单:
"{{ printf \"%.25s\" .Content }}"
答案 1 :(得分:7)
更新:现在,以下代码符合unicode标准,适用于使用国际计划的用户。
需要注意的一点是,下面的bytes.Runes(“string”)是一个O(N)操作,从符文到字符串的转换也是如此,因此这段代码在字符串上循环两次。为PreviewContent()
执行以下代码可能更有效func (c ContentHolder) PreviewContent() string {
var numRunes = 0
for index, _ := range c.Content {
numRunes++
if numRunes > 25 {
return c.Content[:index]
}
}
return c.Content
}
您可以选择此功能的选项。假设您有某种类型的内容持有者,可以使用以下内容:
type ContentHolder struct {
Content string
//other fields here
}
func (c ContentHolder) PreviewContent() string {
// This cast is O(N)
runes := bytes.Runes([]byte(c.Content))
if len(runes) > 25 {
return string(runes[:25])
}
return string(runes)
}
然后您的模板将如下所示:
{{ range .SomeContent }}
....
{{ .PreviewContent }}
....
{{ end }}
另一个选项是创建一个函数,该函数将接受字符串的前25个字符。代码看起来像这样(由@MartinDrLík修改代码,link to code)
package main
import (
"html/template"
"log"
"os"
)
func main() {
funcMap := template.FuncMap{
// Now unicode compliant
"truncate": func(s string) string {
var numRunes = 0
for index, _ := range s {
numRunes++
if numRunes > 25 {
return s[:index]
}
}
return s
},
}
const templateText = `
Start of text
{{ range .}}
Entry: {{.}}
Truncated entry: {{truncate .}}
{{end}}
End of Text
`
infoForTemplate := []string{
"Stackoverflow is incredibly awesome",
"Lorem ipsum dolor imet",
"Some more example text to prove a point about truncation",
"ПриветМирПриветМирПриветМирПриветМирПриветМирПриветМир",
}
tmpl, err := template.New("").Funcs(funcMap).Parse(templateText)
if err != nil {
log.Fatalf("parsing: %s", err)
}
err = tmpl.Execute(os.Stdout, infoForTemplate)
if err != nil {
log.Fatalf("execution: %s", err)
}
}
输出:
Start of text
Entry: Stackoverflow is incredibly awesome
Truncated entry: Stackoverflow is incredib
Entry: Lorem ipsum dolor imet
Truncated entry: Lorem ipsum dolor imet
Entry: Some more example text to prove a point about truncation
Truncated entry: Some more example text to
Entry: ПриветМирПриветМирПриветМирПриветМирПриветМирПриветМир
Truncated entry: ПриветМирПриветМирПриветМ
End of Text
答案 2 :(得分:3)
需要更多魔术用于Unicode字符串
这不正确,请参阅下文
import "unicode/utf8"
func Short( s string, i int) string {
if len( s ) < i {
return s
}
if utf8.ValidString( s[:i] ) {
return s[:i]
}
// The omission.
// In reality, a rune can have 1-4 bytes width (not 1 or 2)
return s[:i+1] // or i-1
}
但上面的i
不是字符的数量。这是字节数。在play.golang.org
我希望这会有所帮助。
已更新:检查字符串长度。请参阅下面的@geoff评论
package main
import "fmt"
func Short( s string, i int ) string {
runes := []rune( s )
if len( runes ) > i {
return string( runes[:i] )
}
return s
}
func main() {
fmt.Println( Short( "Hello World", 5 ) )
fmt.Println( Short( "Привет Мир", 5 ) )
}
但是如果你对字节长度感兴趣:
func truncateStrings(s string, n int) string {
if len(s) <= n {
return s
}
for !utf8.ValidString(s[:n]) {
n--
}
return s[:n]
}
play.golang.org。此函数从不会发生混乱(如果n> = 0),但您可以获得空字符串play.golang.org
另外,请记住这个实验包golang.org/x/exp/utf8string
包utf8string提供了一种通过符文而不是按字节索引字符串的有效方法。
答案 3 :(得分:3)
您可以使用documentation中的slice。以下示例必须有效:
NAME READY STATUS RESTARTS AGE
pod/elasticsearch-0 0/1 Pending 0 45m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/elasticsearch ClusterIP None <none> 9200/TCP,9300/TCP 30h
NAME READY AGE
statefulset.apps/elasticsearch 0/3 45m
Name: elasticsearch-0
Namespace: logging
Priority: 0
Node: <none>
Labels: app=elasticsearch
controller-revision-hash=elasticsearch-6dd997c6d8
statefulset.kubernetes.io/pod-name=elasticsearch-0
Annotations: <none>
Status: Pending
IP:
Controlled By: StatefulSet/elasticsearch
Init Containers:
fix-permissions:
Image: busybox
Port: <none>
Host Port: <none>
Command:
sh
-c
chown -R 1000:1000 /usr/share/elasticsearch/data
Environment: <none>
Mounts:
/usr/share/elasticsearch/data from data (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-gvqz5 (ro)
increase-vm-max-map:
Image: busybox
Port: <none>
Host Port: <none>
Command:
sysctl
-w
vm.max_map_count=262144
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-gvqz5 (ro)
increase-fd-ulimit:
Image: busybox
Port: <none>
Host Port: <none>
Command:
sh
-c
ulimit -n 65536
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-gvqz5 (ro)
Containers:
elasticsearch:
Image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
Ports: 9200/TCP, 9300/TCP
Host Ports: 0/TCP, 0/TCP
Limits:
cpu: 1
Requests:
cpu: 100m
Environment:
cluster.name: k8s-logs
node.name: elasticsearch-0 (v1:metadata.name)
discovery.seed_hosts: elasticsearch-0.elasticsearch,elasticsearch-1.elasticsearch,elasticsearch-2.elasticsearch
cluster.initial_master_nodes: elasticsearch-0,elasticsearch-1,elasticsearch-2
ES_JAVA_OPTS: -Xms512m -Xmx512m
Mounts:
/usr/share/elasticsearch/data from data (rw)
/var/run/secrets/kubernetes.io/serviceaccount from default-token-gvqz5 (ro)
Conditions:
Type Status
PodScheduled False
Volumes:
data:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: data-elasticsearch-0
ReadOnly: false
default-token-gvqz5:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-gvqz5
Optional: false
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m39s (x44 over 64m) default-scheduler pod has unbound immediate PersistentVolumeClaims
答案 4 :(得分:1)
您可以定义一个功能。看看http://golang.org/pkg/text/template/#example_Template_func。
编辑: 在操场上看到它:http://play.golang.org/p/OP2x5vDCtn
答案 5 :(得分:0)
有很多很好的答案,但有时候在不切词的情况下截断会更方便用户。雨果为此提供template function。 但是在Hugo之外很难使用,所以我已经实现了它:
func TruncateByWords(s string, maxWords int) string {
processedWords := 0
wordStarted := false
for i := 0; i < len(s); {
r, width := utf8.DecodeRuneInString(s[i:])
if !isSeparator(r) {
i += width
wordStarted = true
continue
}
if !wordStarted {
i += width
continue
}
wordStarted = false
processedWords++
if processedWords == maxWords {
const ending = "..."
if (i + len(ending)) >= len(s) {
// Source string ending is shorter than "..."
return s
}
return s[:i] + ending
}
i += width
}
// Source string contains less words count than maxWords.
return s
}
这是对此功能的测试:
func TestTruncateByWords(t *testing.T) {
cases := []struct {
in, out string
n int
}{
{"a bcde", "a...", 1},
{"a b", "a b", 2},
{"a b", "a b", 3},
{"a b c", "a b c", 2},
{"a b cd", "a b cd", 2},
{"a b cde", "a b...", 2},
{" a b ", " a b...", 2},
{"AB09C_D EFGH", "AB09C_D...", 1},
{"Привет Гоферам", "Привет...", 1},
{"Here are unicode spaces", "Here are...", 2},
}
for i, c := range cases {
got := TruncateByWords(c.in, c.n)
if got != c.out {
t.Fatalf("#%d: %q != %q", i, got, c.out)
}
}
}
答案 6 :(得分:0)
str := "xxxx"
n := 2
if len(str) > n {
fmt.Println(str[:n])
}
别说我们需要四分之一的ASCII字符串
str[:len(str)/4]