golang text/template的startswith函数

huangapple go评论83阅读模式
英文:

golang text/template startswith function

问题

我在Go的text/template包中没有看到任何类型的startswith函数。这是最好的实现吗?

{{if eq (slice $c 0 5) "begin"}}
英文:

I don't see any type of startswith function in the Go text/template package. Is this the best implementation?

{{if eq (slice $c 0 5) "begin"}}

答案1

得分: 4

没有内置的startswith模板函数。

最干净的方法是注册一个具有该功能的自定义函数:

func main() {
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "hasPrefix": strings.HasPrefix,
    }).Parse(src))

    for _, s := range []string{"foo", "begining"} {
        if err := t.Execute(os.Stdout, s); err != nil {
            panic(err)
        }
    }
}

const src = `{{.}}: {{if hasPrefix . "begin"}}yes{{else}}no{{end}}
`

这将输出(在Go Playground上尝试):

foo: no
begining: yes

如果您不能或不想注册自定义函数,slice可以用于字符串,但必须小心使用:如果输入字符串的长度小于5个字节,您将得到一个模板执行错误!

相反(如果您不想注册自定义函数),我建议使用内置的printf函数,其中_精度_是要比较的字符串的长度。如果输入字符串较短,printf不会引发错误:

{{if eq (printf "%.5s" .) "begin"}}yes{{else}}no{{end}}

这将输出相同的结果。在Go Playground上尝试这个。

请注意,使用hasPrefix更安全、更清晰和更简单,因为我们不需要硬编码前缀的长度(5)。

请注意,使用显式参数索引,我们还可以使此部分动态化:

{{$prefix := "begin"}}{{if eq (printf "%.[1]*s" (len $prefix) .) $prefix}}yes{{else}}no{{end}}

正如您所看到的,我们可以摆脱前缀的硬编码长度5。这同样输出相同的结果,在Go Playground上尝试一下。

最后要注意的一点是,对字符串进行切片时,索引被解释为_字节索引_,而格式字符串中使用的精度被解释为_符文计数_!

英文:

There is no builtin startswith template function.

The cleanest is if you register a custom function with that functionality:

func main() {
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"hasPrefix": strings.HasPrefix,
	}).Parse(src))

	for _, s := range []string{"foo", "begining"} {
		if err := t.Execute(os.Stdout, s); err != nil {
			panic(err)
		}
	}
}

const src = `{{.}}: {{if hasPrefix . "begin"}}yes{{else}}no{{end}}
`

This will output (try it on the Go Playground):

foo: no
begining: yes

If you can't or don't want to register a custom function, slice works for strings, but you must use it with care: if the input string is shorter than 5 bytes, you'll get a template execution error!

Instead (if you don't want to register a custom function), I suggest to use the builtin printf function with precision being the length of the string to compare to. printf will not panic if the input string is shorter:

{{if eq (printf "%.5s" .) "begin"}}yes{{else}}no{{end}}

This outputs the same. Try this one on the Go Playground.

Note that using hasPrefix is safer, cleaner and simpler as we don't have to hard-code the length of the prefix (5).

Note that using explicit argument indices we can also make this part dynamic:

{{$prefix := "begin"}}{{if eq (printf "%.[1]*s" (len $prefix) .) $prefix}}yes{{else}}no{{end}}

As you can see, we could get rid of the hard-coded length of 5 of the prefix. This again outputs the same, try it on the Go Playground.

One last thing to note: slicing a string interprets indices as byte-indices, while the precision used in a format string is interpreted as rune count!

答案2

得分: 0

我认为你是对的。Go的text/template包没有提供内置的startswith函数。要在Go的text/template中检查字符串是否以特定前缀开头,你不能直接使用(slice $c 0 5)结合eq,因为slice函数返回的是一个新的切片,而不是一个字符串。

也许一个使用自定义函数的示例可以是这样的:

package main

import (
	"os"
	"strings"
	"text/template"
)

func StartsWithPrefix(str, prefix string) bool {
	return strings.HasPrefix(str, prefix)
}

func main() {
	tmpl := template.Must(template.New("").Funcs(template.FuncMap{
		"startswith": StartsWithPrefix,
	}).Parse(`{{if startswith .C "begin"}}(Chester's Bennington voice)It starts with "One Thing"{{end}}`))

	data := struct {
		C string
	}{
		C: "beginning bla bla",
	}

	err := tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

在这个示例中,我们定义了StartsWithPrefix函数,将其注册为startswith使用template.FuncMap,然后在模板中使用{{if startswith $c "begin"}}来检查$c的值是否以前缀"begin"开头。如果是,将打印出消息"(Chester's Bennington voice)It starts with 'One Thing'"。

你也可以在Go Playground中检查它 https://go.dev/play/p/hEvhYo_iHhM

英文:

I think that you are right. Go text/template package does not provide a built-in startswith function. To check if a string starts with a specific prefix in Go text/templates, you cannot directly use (slice $c 0 5) in combination with eq because the slice function returns a new slice, not a string.

Maybe an example of how to use a custom function would be like:

package main

import (
	"os"
	"strings"
	"text/template"
)

func StartsWithPrefix(str, prefix string) bool {
	return strings.HasPrefix(str, prefix)
}

func main() {
	tmpl := template.Must(template.New("").Funcs(template.FuncMap{
		"startswith": StartsWithPrefix,
	}).Parse(`{{if startswith .C "begin"}}(Chester's Bennington voice)It starts with "One Thing"{{end}}`))

	data := struct {
		C string
	}{
		C: "beginning bla bla",
	}

	err := tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

In this example, we define the StartsWithPrefix function, register it as startswith using template.FuncMap, and then use {{if startswith $c "begin"}} in the template to check if the value of $c starts with the prefix "begin". If it does, the message "(Chester's Bennington voice)It starts with 'One Thing'" will be printed.

You can also check it in Go playground https://go.dev/play/p/hEvhYo_iHhM

huangapple
  • 本文由 发表于 2023年6月14日 02:57:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76467951.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定