英文:
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"
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论