douqianrou9079 2019-07-21 20:11
浏览 78
已采纳

为什么在使用fmt.Fscanf时出现“输入格式不匹配”​​的提示?

I'm trying to use fmt.Fscanf but I'm having hard time figuring out how. Having the following code:

package main

import (
    "fmt"
    "strings"
)

func main() {
    var host, user, date, httpStr string
    var code, size int

    r := strings.NewReader(`127.0.0.1 - james [09/May/2018:16:00:39 +0000] "GET /report HTTP/1.0" 200 123`)

    _, err := fmt.Fscanf(r, `%s - %s [%s], "%s" %d %d`,
        &host, &user, &date, &httpStr, &code, &size)
    if err != nil {
        fmt.Printf("Failed to parse log line, error: %+v
", err)
        panic(err)
    }

    fmt.Println(host, user, date, httpStr, code, size)

}

Go playground: https://play.golang.org/p/zGxc6MXOF3a

I get:

Failed to parse log line, error: input does not match format
panic: input does not match format

goroutine 1 [running]:
main.main()
        .../fscanf/main.go:19 +0x57b
exit status 2

Why?

  • 写回答

1条回答 默认 最新

  • dourong6054 2019-07-21 21:51
    关注

    The error comes from how Fscanf parses space-separated strings. This becomes an issue when reading the date and HTTP string:

    When it reads the date, instead of reading 09/May/2018:16:00:39 +0000 it will read until the first space: 09/May/2018:16:00:39 then expect ].

    To fix this, it would make sense to parse the string as [%s %s], but this would fail more subtly. It would parse the timezone as +0000] because it stops at the first space, not according to the format string. The same issue occurs with the HTTP string: it stops parsing after the verb GET, then after the route /report, but when reading the protocol it reads HTTP/1.0" not HTTP/1.0.

    A working solution is as follows:

    package main
    
    import (
        "fmt"
        "log"
        "strings"
    )
    
    func main() {
        var host, user, date, tzOffset, verb, route, proto string
        var code, size int
    
        r := strings.NewReader(`127.0.0.1 - james [09/May/2018:16:00:39 +0000] "GET /report HTTP/1.0" 200 123`)
    
        _, err := fmt.Fscanf(r, `%s - %s %s %s %s %s %s %d %d`,
            &host, &user, &date, &tzOffset, &verb, &route, &proto, &code,
            &size)
    
        if err != nil {
            log.Fatal(err)
        }
    
        date = date[1:] + " " + tzOffset[:len(tzOffset)-1]
        httpString := verb[1:] + " " + route + " " + proto[:len(proto)-1]
    
        fmt.Println(host, user, date, httpString, code, size)
    }
    

    Here we ignore the brackets and quotes around the date and HTTP string when parsing, then remove them afterwards.

    Output:

    127.0.0.1 james 09/May/2018:16:00:39 +0000 GET /report HTTP/1.0 200 123
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 对于相关问题的求解与代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 信号傅里叶变换在matlab上遇到的小问题请求帮助
  • ¥15 保护模式-系统加载-段寄存器
  • ¥15 电脑桌面设定一个区域禁止鼠标操作
  • ¥15 求NPF226060磁芯的详细资料
  • ¥15 使用R语言marginaleffects包进行边际效应图绘制
  • ¥20 usb设备兼容性问题
  • ¥15 错误(10048): “调用exui内部功能”库命令的参数“参数4”不能接受空数据。怎么解决啊
  • ¥15 安装svn网络有问题怎么办