部分Fscanf结果

问题描述 投票:0回答:2

我必须遵循尝试解析日期字符串的代码:

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 做我想要的事情?如果不是,我应该如何解析这个字符串?

go
2个回答
0
投票

我认为你最好的选择是使用正则表达式(包regexp)预先验证字符串:

var dateFormat = regexp.MustCompile(`^\d{4}-\d{2}$`)


if !dateFormat.MatchString(s) {
    ... complain ...
}

演示:无效案例

24-02
有效案例
2024-02
。 (请注意,我还随意从
bytes.NewReader
+
fmt.Fscanf
切换到
fmt.Sscanf
,它直接扫描字符串。)


0
投票

在 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)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.