package main
import (
"bytes"
"fmt"
)
func main() {
s := "24-02"
r := bytes.NewReader([]byte(s))
var year uint
var month uint
_, err := fmt.Fscanf(r, "%04d-%02d", &year, &month)
if err != nil {
panic(err)
} else {
fmt.Printf("%04d-%02d", year, month)
}
}
输出为:
0024-02
我预计 Fscanf 会失败,因为年份字段不是四个字符长。
有没有办法让 Fscanf 做我想要的事情?如果不是,我应该如何解析这个字符串?
我认为你最好的选择是使用正则表达式(包regexp)预先验证字符串:
var dateFormat = regexp.MustCompile(`^\d{4}-\d{2}$`)
if !dateFormat.MatchString(s) {
... complain ...
}
演示:无效案例
24-02
; 有效案例2024-02
。 (请注意,我还随意从 bytes.NewReader
+ fmt.Fscanf
切换到 fmt.Sscanf
,它直接扫描字符串。)
在 Golang 中,
fmt.Fscanf
函数用于从流(如 os.Stdin
或文件)读取输入并根据给定的格式说明符解析它。当您指定 %d
时,它期望读取整数值。但是,它并不严格要求整数恰好是四个字符。相反,它会读取字符,直到遇到不能属于整数的字符(例如空格或换行符)。
修改您的代码如下,使用 "%04s-%02d" 而不是 "%04d-%02d",
%04d
:此格式说明符期望读取恰好包含四个字符的整数。如果输入不正好有四个字符,只要它可以读取格式字符串中每个说明符的内容,它仍然会认为它是成功的匹配。在您的原始代码中,由于有足够的字符来满足 %04d
说明符(即使它不完全是四个字符),因此 fmt.Fscanf
认为它是成功的匹配。
%04s
:此格式说明符期望读取最大长度为四个字符的字符串。与 %04d 不同,它不要求输入正好是四个字符长。如果输入字符串短于四个字符,它仍然会认为它是成功的匹配。如果输入字符串超过四个字符,它将仅读取前四个字符并认为其匹配成功。通过使用 %04s
而不是 %04d
,您可以确保如果年份字段的长度不是正好四个字符,则 fmt.Fscanf
将失败。
package main
import (
"bytes"
"fmt"
)
func main() {
s := "2400-02"
r := bytes.NewReader([]byte(s))
var year string
var month uint
_, err := fmt.Fscanf(r, "%04s-%02d", &year, &month)
if err != nil {
panic(err)
} else {
fmt.Printf("%s-%02d", year, month)
}
}