Go 如何忽略fmt.Sprintf的额外字段

Go 如何忽略fmt.Sprintf的额外字段,go,Go,我有一个Golang程序,它从命令行读取字符串参数并将其传递给fmt.Sprintf函数。假设tmp_str是命令行中的目标字符串 package main import "fmt" func main() { tmp_str := "hello %s" str := fmt.Sprintf(tmp_str, "world") fmt.Println(str) } 在某些情况下,程序将传递一个完整的字符串,如“Hello Friends”,而不是字符串模板。。程序会

我有一个Golang程序,它从命令行读取字符串参数并将其传递给fmt.Sprintf函数。假设tmp_str是命令行中的目标字符串

package main

import "fmt"

func main() {
    tmp_str := "hello %s"
    str := fmt.Sprintf(tmp_str, "world")
    fmt.Println(str)
}
在某些情况下,程序将传递一个完整的字符串,如“Hello Friends”,而不是字符串模板。。程序会死机并返回:

你好,朋友们%!(额外字符串=世界)

那么,如何忽略fmt.Sprintf的额外字段呢?

您不能这样做

您必须找到不同的解决方案。

我同意,但您可以检查输入字符串:

package main

import (
    "fmt"
    "strings"
)

func main() {
    tmp_str := "hello %s"

    res := tmp_str
    if strings.Count(tmp_str, "%s") == 1 {
        res = fmt.Sprintf(tmp_str, "world")
    }
    fmt.Println(res)
}

是的,您可以通过对传递给variadic
Sprintf
函数的参数进行切片来实现:

func TruncatingSprintf(str string, args ...interface{}) (string, error) {
    n := strings.Count(str, "%s")
    if n > len(args) {
        return "", errors.New("Unexpected string:" + str)
    }
    return fmt.Sprintf(str, args[:n]...), nil
}

func main() {
    tmp_str := "hello %s %s %s"         // don't hesitate to add many %s here
    str, err := TruncatingSprintf(tmp_str, "world") // or many arguments here
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(str)
}

(即使参数多于%s,也会有不同版本的输出)


但是您通常不使用动态格式化字符串,这是不安全的,如果您想要接受任何字符串,您还应该调整此代码,使其在
%%s
上无阻塞。如果您冒险这么做,那么您可能应该看看(这将允许您使用命名字符串,因此缺少的字符串不必是最后一个)。

在这种特殊情况下,您可以要求命令行用户始终提供%s动词,并解释他们可以将字符串截断为零长度:

Hello Friends%.0s
甚至更短:

Hello Friends%.s
输出是简单的:

朋友们好

我使用这个(可能可以扩展)


我不确定Go的fmt库是否存在与C相同的安全问题,但为了安全起见,您不应该使用来自不可信源的格式字符串。在C语言中,这会导致信息泄漏,比如打印敏感堆栈数据,甚至数据覆盖和代码执行。@ZanLynx感谢您的更新。我只是简化了问题。该程序肯定不会向其他人公开。@Zan Lynx在Go的fmt库和其他常规Go代码中没有此类安全问题。这并不意味着随意处理格式字符串是一个好主意。这是一个注释,而不是答案。为什么会这样?最初的问题是关于如何使
fmt.Printf
忽略额外的参数,而这是无法做到的。不同的解决方案是预处理参数,但这是编程101,与
fmt.Printf
无关。答案很好。添加了一些OP可以扩展的错误处理:@william.taylor.09好主意。我将您的错误处理添加到答案中,这样就不会有人错过它。但请注意,如果%s多于参数,则可以考虑添加索引占位符帮助:
fmt.Sprintf(“Hello”+“%[2]s”,“World”,”)
感谢您的回复。我对Golang有点陌生。我觉得你的回答很鼓舞人心!在我的特殊情况下,这是完美的。简单明了。这对我来说也非常有效。我还注意到,可以使用“%.T”忽略任何数据类型(不仅仅是字符串!)。例如,
fmt.Printf(“arg1=%s,arg2=%.T,arg3=%.T,arg4=%.T,arg=%s”,“arg1”,2.123,true,“arg4”,“arg5”)
=>“arg1=arg1,arg2=,arg3=,arg4=,arg5”(请参阅:和)。然而,在这种方法中,有一个“Printf format%.T有一个无法识别的标志。”Go vet的错误,我还没有解释。谢谢Stein和Roshambo!:)
Sprintf("Hello"+"%[2]s", "World", "")
Sprintf("Hello %s"+"%[2]s", "World", "")