如何动态地将值传递给 Sprintf 或 Printf 函数?

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

how to dynamically pass values to Sprintf or Printf

问题

如果我想填充一个字符串,我可以使用类似这样的代码:

package main

import (
	"fmt"
)

func main() {
	x := fmt.Sprintf("%+20s", "Hello World!")
	fmt.Println(x)
}

从https://golang.org/pkg/fmt/中可以看到:

+:对于数字值,始终打印符号;对于%q(%+q),保证输出仅为ASCII字符。
-:在右侧填充空格,而不是左侧(左对齐字段)。

但是,如果我想动态更改填充大小,我该如何传递值?

我的第一个尝试是:

x := fmt.Sprintf("%+%ds", 20, "Hello World!")

但是我得到了这个结果:

%ds%!(EXTRA int=20, string=Hello World!)

有没有一种方法可以在不创建自定义填充函数的情况下实现这一点,该函数可以在左侧或右侧添加空格,可能使用for循环:

for i := 0; i < n; i++ {
	out += str
}
英文:

If I want to pad a string I could use something like this:

https://play.golang.org/p/ATeUhSP18N

package main

import (
	&quot;fmt&quot;
)

func main() {
	x := fmt.Sprintf(&quot;%+20s&quot;, &quot;Hello World!&quot;)
	fmt.Println(x)
}

From https://golang.org/pkg/fmt/

 +	always print a sign for numeric values; 
    guarantee ASCII-only output for %q (%+q)
 -	pad with spaces on the right rather than the left (left-justify the field)

But If I would like to dynamically change the pad size how could I pass the value ?

My first guest was:

x := fmt.Sprintf(&quot;%+%ds&quot;, 20, &quot;Hello World!&quot;)

But I get this:

%ds%!(EXTRA int=20, string=Hello World!)

Is there a way of doing this without creating a custom pad function what would add spaces either left or right probably using a for loop:

for i := 0; i &lt; n; i++ {
	out += str
}

答案1

得分: 38

使用 * 来告诉 Sprintf 从参数列表中获取格式化参数:

fmt.Printf("%*s\n", 20, "Hello World!")

完整代码请参考 play.golang.org

英文:

Use * to tell Sprintf to get a formatting parameter from the argument list:

fmt.Printf(&quot;%*s\n&quot;, 20, &quot;Hello World!&quot;)

Full code on play.golang.org

答案2

得分: 11

转到:https://golang.org/pkg/fmt/,并向下滚动,直到找到以下内容:

> fmt.Sprintf("%[3].[2]1f", 12.0, 2, 6)
>
> 等同于
>
> fmt.Sprintf("%6.2f", 12.0)
>
> 将产生 " 12.00"。因为显式索引会影响后续的动词,所以可以使用此表示法通过将第一个要重复的参数的索引重置来多次打印相同的值。

这听起来像是你想要的。

关于使用参数设置字段宽度和精度的描述的真正核心在上面更进一步:

> 宽度和精度以 Unicode 代码点(即符文)为单位进行测量。(这与 C 的 printf 不同,C 的单位始终以字节为单位。)两个标志中的任何一个或两个都可以用字符“*”替换,从而使它们的值从下一个操作数中获取,该操作数必须是 int 类型。

上面的示例只是额外使用了对参数列表的显式索引,这有时很方便,并允许您重用相同的宽度和精度值进行更多的转换。

因此,您还可以编写:

    fmt.Sprintf(&quot;*.*f&quot;, 6, 2, 12.0)
英文:

Go to: https://golang.org/pkg/fmt/
and scroll down until you find this:

> fmt.Sprintf("%[3].[2]1f", 12.0, 2, 6)
>
> equivalent to
>
> fmt.Sprintf("%6.2f", 12.0)
>
> will yield " 12.00". Because an explicit index affects subsequent verbs,
> this notation can be used to print the same values multiple times by
> resetting the index for the first argument to be repeated

This sounds like what you want.

The real core of the description of using arguments to set field width and precision occurs further above:

> Width and precision are measured in units of Unicode code points, that
> is, runes. (This differs from C's printf where the units are always
> measured in bytes.) Either or both of the flags may be replaced with
> the character '*', causing their values to be obtained from the next
> operand, which must be of type int.

The example above is just using explicit indexing into the argument list in addition, which is sometimes nice to have and allows you to reuse the same width and precision values for more conversions.

So you could also write:

    fmt.Sprintf(&quot;*.*f&quot;, 6, 2, 12.0)

huangapple
  • 本文由 发表于 2017年2月18日 05:55:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/42308070.html
匿名

发表评论

匿名网友

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

确定