Sscanf无法正确匹配单引号。

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

Sscanf not properly matching single quotes

问题

我正在处理一些Go代码,但是我在弄清楚为什么我的字符串没有被正确扫描时遇到了麻烦。

我得到了一个看起来像这样的字符串:

"ERROR: 1: something happened 'here'"

我尝试像这样进行扫描:

n, err := fmt.Sscanf("ERROR: 1: something happened 'here'", "ERROR: 1: something happened '%50s'", &value)

然而,每次我检查值的结果时,我得到的是这样的:

here'

最后的单引号被保留了下来。

有什么办法可以修复这个问题吗?我认为这种情况不会是非确定性的,因为函数在不包括引号的情况下无法完成格式化。

当然,我可以简单地删除最后一个字符,但我更喜欢一个基于fmt的解决方案。

英文:

I working on some Go code but I am having troubles figuring out why my string isn't being scanned correctly.

I'm given a string that looks like this:

"ERROR: 1: something happened 'here'"

I'm trying to scan it like this:

n, err := fmt.Sscanf("ERROR: 1: something happened 'here'", "ERROR: 1: something happened '%50s'", &value)

However, every time I check the result of the value, I get something like this:

here'

Where the last single quote is left in.

Any idea how to fix this? I figured this case wouldn't be non-deterministic because the function can't complete formatting without including the quote.

Of course, I can simply remove the last character, but I would prefer a fmt-based solution.

答案1

得分: 2

内置的fmt.Scanner没有办法做到你想做的事情。如果目标文本被双引号包裹,你可以使用%q格式化符号。

另外,如果目标是一个被单引号包裹的单个字符,你可以使用text/scanner。但是因为你的目标既不是这两种情况,所以没有内置的方法可以实现。因此,你的选择是使用regexp、带有自定义扫描器的bufio,或者仅仅使用strings.Split。如果你坚持使用fmt,你可以使用自定义的扫描器,但这可能是所有选项中最糟糕的选择:

package main
import "fmt"

type quote struct { tok string }

func (q *quote) Scan(state fmt.ScanState, verb rune) error {
   tok, err := state.Token(false, func(r rune) bool {
      return r != 0x27 // '
   })
   if err != nil {
      return err
   }
   if _, _, err := state.ReadRune(); err != nil {
      if len(tok) == 0 {
         panic(err)
      }
   }
   q.tok = string(tok)
   return nil
}

示例:

package main

import (
   "fmt"
   "strings"
)

func main() {
   r := strings.NewReader("ERROR: 1: something happened 'here'")
   for {
      var q quote
      _, err := fmt.Fscan(r, &q)
      if err != nil {
         break
      }
      fmt.Printf("%q\n", q.tok)
   }
}

结果:

"ERROR: 1: something happened "
"here"
英文:

The builtin fmt.Scanner has no way to do what you're trying to do. If the target text was wrapped in double quotes, you could use the %q specifier.

Alternatively, if the target was a single wrapped character, you could use text/scanner. But because your target is neither of those, there's nothing built in. So, your options are regexp, or bufio with a custom scanner, or even just strings.Split. If you insist on using fmt you can do a custom scanner, but it's probably the worst option of everything:

package main
import "fmt"

type quote struct { tok string }

func (q *quote) Scan(state fmt.ScanState, verb rune) error {
   tok, err := state.Token(false, func(r rune) bool {
      return r != 0x27 // '
   })
   if err != nil {
      return err
   }
   if _, _, err := state.ReadRune(); err != nil {
      if len(tok) == 0 {
         panic(err)
      }
   }
   q.tok = string(tok)
   return nil
}

Example:

package main

import (
   "fmt"
   "strings"
)

func main() {
   r := strings.NewReader("ERROR: 1: something happened 'here'")
   for {
      var q quote
      _, err := fmt.Fscan(r, &q)
      if err != nil {
         break
      }
      fmt.Printf("%q\n", q.tok)
   }
}

Result:

"ERROR: 1: something happened "
"here"

huangapple
  • 本文由 发表于 2021年7月21日 01:30:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/68459099.html
匿名

发表评论

匿名网友

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

确定