使用fmt.Sscanf报unexpected EOF?

yecz · 2022-09-21 17:23:51 · 1768 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2022-09-21 17:23:51 的主题,其中的信息可能已经有所发展或是发生改变。

func main() {
    var (
        str    = "a=aaa,b=bbb,c=ccc"
        format = "a=%s,b=%s,c=%s"

        a string
        b string
        c string
    )

    if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil {
        log.Fatal(err)
    }

    log.Println("a:", a)
    log.Println("b:", b)
    log.Println("c:", c)
}
output: 2022/09/21 17:18:41 unexpected EOF

这是什么问题?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1768 次点击  
加入收藏 微博
6 回复  |  直到 2022-09-21 18:19:06
Mericusta
Mericusta · #1 · 3年之前

// Sscanf scans the argument string, storing successive space-separated // values into successive arguments as determined by the format. It // returns the number of items successfully parsed. // Newlines in the input must match newlines in the format.

Mericusta
Mericusta · #2 · 3年之前

// Sscanf scans the argument string, storing successive space-separated

// values into successive arguments as determined by the format. It

// returns the number of items successfully parsed.

// Newlines in the input must match newlines in the format.

func Sscanf(str string, format string, a ...any) (n int, err error) {

return Fscanf((*stringReader)(&str), format, a...)

}

jan-bar
jan-bar · #3 · 3年之前

当你执行下面代码会发现,第一个a把剩余所有字符串都获取了

package main

import (
    "fmt"
    "log"
)

func main() {
    var (
        str    = "a=aaa,b=bbb,c=ccc"
        format = "a=%s,b=%s,c=%s"

        a string
        b string
        c string
    )

    if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil {
        log.Println(err)
    }

    log.Println("a:", a)
    log.Println("b:", b)
    log.Println("c:", c)
}

结果如下

2022/09/21 17:50:04 unexpected EOF
2022/09/21 17:50:04 a: aaa,b=bbb,c=ccc
2022/09/21 17:50:04 b:
2022/09/21 17:50:04 c:

你可以增加空格,因为scanf默认都是已空格或者制表符之类的作为分隔,下面这种方式需要两种字符串都已空格分开

package main

import (
    "fmt"
    "log"
)

func main() {
    var (
        str    = "a=aaa ,b=bbb ,c=ccc"
        format = "a=%s ,b=%s ,c=%s"

        a string
        b string
        c string
    )

    if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil {
        log.Println(err)
    }

    log.Println("a:", a)
    log.Println("b:", b)
    log.Println("c:", c)
}

结果如下
2022/09/21 17:54:58 a: aaa
2022/09/21 17:54:58 b: bbb
2022/09/21 17:54:58 c: ccc

下面方法我将扫描分隔符改为逗号,完全满足你的需求

package main

import (
    "fmt"
    "log"
)

func main() {
    var (
        str    = "a=aaa,b=bbb,c=ccc"
        format = "a=%s,b=%s,c=%s"

        a, b, c string
    )

    if _, err := fmt.Sscanf(str, format, (*mm)(&a), (*mm)(&b), (*mm)(&c)); err != nil {
        log.Println(err)
    }

    log.Println("a:", a)
    log.Println("b:", b)
    log.Println("c:", c)
}

type mm string

func (m *mm) Scan(state fmt.ScanState, verb rune) error {
    tok, err := state.Token(true, func(r rune) bool {
        return r != ',' // 默认string以空格分隔,我这里改为用逗号分隔
    })
    if err != nil {
        return err
    }
    *m = mm(tok)
    return nil
}


结果如下

2022/09/21 17:55:28 a: aaa
2022/09/21 17:55:28 b: bbb
2022/09/21 17:55:28 c: ccc

我又修改了下,感觉把类型改为自定义使用起来比较麻烦。这下更完美了。

@Mericusta @yecz

yecz
yecz · #4 · 3年之前
MericustaMericusta #2 回复

// Sscanf scans the argument string, storing successive space-separated // values into successive arguments as determined by the format. It // returns the number of items successfully parsed. // Newlines in the input must match newlines in the format. func Sscanf(str string, format string, a ...any) (n int, err error) { return Fscanf((*stringReader)(&str), format, a...) }

改成纯空格分隔的确实可以,但是上面的例子改成数值型也可以:

func main() {
    var (
        str    = "a=111,b=222,c=333"
        format = "a=%d,b=%d,c=%d"

        a int
        b int
        c int
    )

    if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil {
        log.Fatal(err)
    }

    log.Println("a:", a)
    log.Println("b:", b)
    log.Println("c:", c)
}

output:

2022/09/21 17:57:21 a: 111
2022/09/21 17:57:21 b: 222
2022/09/21 17:57:21 c: 333
yecz
yecz · #5 · 3年之前
jan-barjan-bar #3 回复

当你执行下面代码会发现,第一个`a`把剩余所有字符串都获取了 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa,b=bbb,c=ccc" format = "a=%s,b=%s,c=%s" a string b string c string ) if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } 结果如下 2022/09/21 17:50:04 unexpected EOF 2022/09/21 17:50:04 a: aaa,b=bbb,c=ccc 2022/09/21 17:50:04 b: 2022/09/21 17:50:04 c: ``` 你可以增加空格,因为`scanf`默认都是已空格或者制表符之类的作为分隔,下面这种方式需要两种字符串都已空格分开 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa ,b=bbb ,c=ccc" format = "a=%s ,b=%s ,c=%s" a string b string c string ) if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } 结果如下 2022/09/21 17:54:58 a: aaa 2022/09/21 17:54:58 b: bbb 2022/09/21 17:54:58 c: ccc ``` 下面方法我将扫描分隔符改为逗号,完全满足你的需求 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa,b=bbb,c=ccc" format = "a=%s,b=%s,c=%s" a, b, c string ) if _, err := fmt.Sscanf(str, format, (*mm)(&a), (*mm)(&b), (*mm)(&c)); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } type mm string func (m *mm) Scan(state fmt.ScanState, verb rune) error { tok, err := state.Token(true, func(r rune) bool { return r != ',' // 默认string以空格分隔,我这里改为用逗号分隔 }) if err != nil { return err } *m = mm(tok) return nil } 结果如下 2022/09/21 17:55:28 a: aaa 2022/09/21 17:55:28 b: bbb 2022/09/21 17:55:28 c: ccc ``` 我又修改了下,感觉把类型改为自定义使用起来比较麻烦。这下更完美了。 @Mericusta @yecz

大佬太棒了👍👍👍

Mericusta
Mericusta · #6 · 3年之前
jan-barjan-bar #3 回复

当你执行下面代码会发现,第一个`a`把剩余所有字符串都获取了 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa,b=bbb,c=ccc" format = "a=%s,b=%s,c=%s" a string b string c string ) if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } 结果如下 2022/09/21 17:50:04 unexpected EOF 2022/09/21 17:50:04 a: aaa,b=bbb,c=ccc 2022/09/21 17:50:04 b: 2022/09/21 17:50:04 c: ``` 你可以增加空格,因为`scanf`默认都是已空格或者制表符之类的作为分隔,下面这种方式需要两种字符串都已空格分开 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa ,b=bbb ,c=ccc" format = "a=%s ,b=%s ,c=%s" a string b string c string ) if _, err := fmt.Sscanf(str, format, &a, &b, &c); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } 结果如下 2022/09/21 17:54:58 a: aaa 2022/09/21 17:54:58 b: bbb 2022/09/21 17:54:58 c: ccc ``` 下面方法我将扫描分隔符改为逗号,完全满足你的需求 ```go package main import ( "fmt" "log" ) func main() { var ( str = "a=aaa,b=bbb,c=ccc" format = "a=%s,b=%s,c=%s" a, b, c string ) if _, err := fmt.Sscanf(str, format, (*mm)(&a), (*mm)(&b), (*mm)(&c)); err != nil { log.Println(err) } log.Println("a:", a) log.Println("b:", b) log.Println("c:", c) } type mm string func (m *mm) Scan(state fmt.ScanState, verb rune) error { tok, err := state.Token(true, func(r rune) bool { return r != ',' // 默认string以空格分隔,我这里改为用逗号分隔 }) if err != nil { return err } *m = mm(tok) return nil } 结果如下 2022/09/21 17:55:28 a: aaa 2022/09/21 17:55:28 b: bbb 2022/09/21 17:55:28 c: ccc ``` 我又修改了下,感觉把类型改为自定义使用起来比较麻烦。这下更完美了。 @Mericusta @yecz

学到了,厉害

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传