与Go中的Python string.format等效?
在Python中,可以执行以下操作:与Go中的Python string.format等效?,python,string,go,Python,String,Go,在Python中,可以执行以下操作: "File {file} had error {error}".format(file=myfile, error=err) 或者这个: "File %(file)s had error %(error)s" % {"file": myfile, "error": err} 在Go中,最简单的选项是: fmt.Sprintf("File %s had error %s", myfile, err) 这不允许您交换格式字符串中参数的顺序,这是您需要做的。
"File {file} had error {error}".format(file=myfile, error=err)
或者这个:
"File %(file)s had error %(error)s" % {"file": myfile, "error": err}
在Go中,最简单的选项是:
fmt.Sprintf("File %s had error %s", myfile, err)
这不允许您交换格式字符串中参数的顺序,这是您需要做的。Go确实有模板
包,它需要如下内容:
package main
import (
"bytes"
"text/template"
"os"
)
func main() {
type Params struct {
File string
Error string
}
var msg bytes.Buffer
params := &Params{
File: "abc",
Error: "def",
}
tmpl, _ := template.New("errmsg").Parse("File {{.File}} has error {{.Error}}")
tmpl.Execute(&msg, params)
msg.WriteTo(os.Stdout)
}
这似乎是一个很长的路要走的错误消息。是否有更合理的选项允许我独立于顺序给出字符串参数?我不知道命名参数的任何简单方法,但您可以使用显式参数索引轻松更改参数的顺序: 发件人: 在Printf、Sprintf和Fprintf中,默认行为是每个格式化谓词格式化调用中传递的连续参数。但是,动词前面的符号[n]表示要格式化第n个索引参数。宽度或精度的“*”前面的相同符号选择保存该值的参数索引。在处理括号内的表达式[n]后,后续动词将使用参数n+1、n+2等,除非另有指示 然后你可以,即:
fmt.Printf("File %[2]s had error %[1]s", err, myfile)
该参数也可以是一个映射,因此,如果您不介意每次使用时解析每个错误格式,则以下函数将起作用:
package main
import (
"bytes"
"text/template"
"fmt"
)
func msg(fmt string, args map[string]interface{}) (str string) {
var msg bytes.Buffer
tmpl, err := template.New("errmsg").Parse(fmt)
if err != nil {
return fmt
}
tmpl.Execute(&msg, args)
return msg.String()
}
func main() {
fmt.Printf(msg("File {{.File}} has error {{.Error}}\n", map[string]interface{} {
"File": "abc",
"Error": "def",
}))
}
它仍然比我想要的要多一些,但我想它比其他一些选项要好。您可以将map[string]接口{}
转换为本地类型,并将其进一步简化为:
type P map[string]interface{}
fmt.Printf(msg("File {{.File}} has error {{.Error}}\n", P{
"File": "abc",
"Error": "def",
}))
带字符串。替换器
使用,实现你想要的格式化程序是非常简单和紧凑的
func main() {
file, err := "/data/test.txt", "file not found"
log("File {file} had error {error}", "{file}", file, "{error}", err)
}
func log(format string, args ...string) {
r := strings.NewReplacer(args...)
fmt.Println(r.Replace(format))
}
输出(在上尝试):
我们可以通过在log()
函数中自动将括号添加到参数名称中,使其更易于使用:
func main() {
file, err := "/data/test.txt", "file not found"
log2("File {file} had error {error}", "file", file, "error", err)
}
func log2(format string, args ...string) {
for i, v := range args {
if i%2 == 0 {
args[i] = "{" + v + "}"
}
}
r := strings.NewReplacer(args...)
fmt.Println(r.Replace(format))
}
输出(在上尝试):
是的,您可以说它只接受string
参数值。这是真的。如果再改进一点,情况就不会是这样了:
func main() {
file, err := "/data/test.txt", 666
log3("File {file} had error {error}", "file", file, "error", err)
}
func log3(format string, args ...interface{}) {
args2 := make([]string, len(args))
for i, v := range args {
if i%2 == 0 {
args2[i] = fmt.Sprintf("{%v}", v)
} else {
args2[i] = fmt.Sprint(v)
}
}
r := strings.NewReplacer(args2...)
fmt.Println(r.Replace(format))
}
输出(在上尝试):
此函数的一个变体,用于将参数接受为map[string]接口{}
,并将结果返回为字符串
:
type P map[string]interface{}
func main() {
file, err := "/data/test.txt", 666
s := log33("File {file} had error {error}", P{"file": file, "error": err})
fmt.Println(s)
}
func log33(format string, p P) string {
args, i := make([]string, len(p)*2), 0
for k, v := range p {
args[i] = "{" + k + "}"
args[i+1] = fmt.Sprint(v)
i += 2
}
return strings.NewReplacer(args...).Replace(format)
}
试穿一下
使用文本/模板
您的模板解决方案或提案也过于冗长。它可以写得如此紧凑(省略错误检查):
输出(在上尝试):
如果要返回字符串
(而不是将其打印到标准输出),可以这样做(在上尝试):
使用显式参数索引
另一个答案中已经提到了这一点,但为了完成这一点,要知道相同的显式参数索引可以被任意次数使用,从而导致相同的参数被多次替换。在这个问题中了解更多信息:唉,Go for string interpolation中没有内置的函数和命名参数。但你不是唯一一个遭受痛苦的人:)有些包应该存在,例如:。或者,如果你喜欢冒险,你可以自己写这样一个助手,因为这个概念其实很简单
干杯,
Dennis您可以非常接近那种甜美的python格式化体验:
message := FormatString("File {file} had error {error}", Items{"file"=myfile, "error"=err})
在代码中的某个地方声明以下内容:
type Items map[string]interface{}
func FormatString(template string, items Items) string {
for key, value := range items {
template = strings.ReplaceAll(template, fmt.Sprintf("{%v}", key), fmt.Sprintf("%v", value))
}
return template
}
- 您可以尝试使用库来实现替换字段,该库由大括号
{}
格式字符串包围,类似于Python格式
工作代码示例:
主程序包
进口(
“fmt”
“gitlab.com/tymonx/go formatter/formatter”
)
func main(){
格式化,err:=formatter.Format(“命名占位符{file}:{line}:{function}():”,formatter.Named{
"行":3,,
“函数”:“func1”,
“文件”:“目录/文件”,
})
如果错误!=零{
恐慌(错误)
}
格式打印项次(格式化)
}
输出:
Named placeholders dir/file:3:func1():
这很有趣。下面我提供一些例子
用法
func TestFString(t*testing.t){
//例1
fs:=&FString{}
fs.MustCompile(`Name:{{.Name}}Msg:{{{.Msg}}}`,nil)
fs.MustRender(映射[字符串]接口{}{
“姓名”:“卡森”,
“Msg”:123,
})
assert.Equal(t,“Name:Carson Msg:123”,fs.Data)
财政司司长
//示例2(带FuncMap)
funcMap:=模板。funcMap{
“最大”:func(片[]浮点32)浮点32{
如果len(slice)==0{
恐慌(错误。新建(“空切片”))
}
最大值:=切片[0]
对于u,val:=范围片[1:]{
如果val>max{
max=val
}
}
返回最大值
},
“sayHello”:func()字符串{
回复“你好”
},
}
fs.MustCompile(“{-if gt.Age 80-}Old{{else}}Young{{-end-}}”+/-”用于删除空空间
“{{sayHello}}{{maxist.Numbers}}}”,//使用您创建的函数。
(地图)
fs.MustRender(上下文){
“年龄”:90岁,
“数字”:[]32{3,9,13.9,2.1,7},
})
assert.Equal(t,“Old Hello 13.9”,fs.Data)
}
解放党
包utils
进口(
“文本/模板”
)
类型上下文映射[字符串]接口{}
类型FString结构{
数据串
template*template.template
}
func(fs*FString)必须编译(expr string,funcMap template.funcMap){
fs.template=template.Must(template.New(“f-string”)。
Funcs(funcMap)。
解析(expr))
}
func(fs*FString)写入(b[]字节)(n int,err error){
fs.Data+=字符串(b)
返回len(b),无
}
func(fs*FString)呈现(上下文映射[string]接口{})错误{
如果错误:=fs.template.Execute(fs,context);错误!=nil{
返回错误
}
归零
}
func(fs*FString)MustRender(上下文){
如果err:=fs.Render(上下文);err!=nil{
恐慌(错误)
}
}
func(fs*FString)Clear()字符串{
//返回数据并清除它
out:=fs.Data
fs.Data=“”
返回
}
重要的
type P map[string]interface{}
func main() {
file, err := "/data/test.txt", 666
log4("File {{.file}} has error {{.error}}", P{"file": file, "error": err})
}
func log4(format string, p P) {
t := template.Must(template.New("").Parse(format))
t.Execute(os.Stdout, p)
}
File /data/test.txt has error 666
func log5(format string, p P) string {
b := &bytes.Buffer{}
template.Must(template.New("").Parse(format)).Execute(b, p)
return b.String()
}
message := FormatString("File {file} had error {error}", Items{"file"=myfile, "error"=err})
type Items map[string]interface{}
func FormatString(template string, items Items) string {
for key, value := range items {
template = strings.ReplaceAll(template, fmt.Sprintf("{%v}", key), fmt.Sprintf("%v", value))
}
return template
}
Named placeholders dir/file:3:func1():