Ответ 1
Вы можете использовать printf
в шаблонах, который действует как fmt.Sprintf
. В вашем случае обрезка строки будет такой же простой, как:
"{{ printf \"%.25s\" .Content }}"
В golang есть способ обрезать текст в html-шаблоне?
Например, в моем шаблоне есть следующее:
{{ range .SomeContent }}
....
{{ .Content }}
....
{{ end }
{{ .Content }}
производит: Interdum et malesuada fames ac ante ipsum primis в 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 - вульгатная вульгатная утилита.
Я хотел бы уменьшить это до 25 символов.
Вы можете использовать printf
в шаблонах, который действует как fmt.Sprintf
. В вашем случае обрезка строки будет такой же простой, как:
"{{ printf \"%.25s\" .Content }}"
Обновление: Теперь код ниже соответствует юникоду для тех, кто работает с международными программами.
Следует отметить, что 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 символов строки. Код для этого выглядит так (пересмотр кода @Martin DrLík, ссылка на код)
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
Вы можете определить функцию. Посмотрите http://golang.org/pkg/text/template/#example_Template_func.
Изменить: Посмотрите на игровой площадке: http://play.golang.org/p/OP2x5vDCtn
Требуется больше магии для строк 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 обеспечивает эффективный способ индексирования строк по rune, а не по байтам.
Есть много хороших ответов, но иногда это более удобно для усечения без сокращения слов. Hugo предлагает функцию шаблона для него. Но это трудно использовать за пределами 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)
}
}
}