我正在尝试在字符串中找到命名捕获组的开头,以创建一个简单的解析器(请参阅related question)。为此,extract
函数会记住last4
变量中最后一个字符。如果最后4个字符等于“(?P<”则它是捕获组的开头:
package main
import "fmt"
const sample string = `/(?P<country>m((a|b).+)(x|y)n)/(?P<city>.+)`
func main() {
extract(sample)
}
func extract(regex string) {
last4 := new([4]int32)
for _, c := range regex {
last4[0], last4[1], last4[2], last4[3] = last4[1], last4[2], last4[3], c
last4String := fmt.Sprintf("%c%c%c%c\n", last4[0], last4[1], last4[2], last4[3])
if last4String == "(?P<" {
fmt.Print("start of capturing group")
}
}
}
http://play.golang.org/p/pqA-wCuvux
但这段代码什么都没打印! last4String == "(?P<"
永远不会成立,但如果我在循环中打印last4String
,则此子句会出现在输出中。如何比较Go中的字符串?
有没有更优雅的方法将int32数组转换为字符串而不是fmt.Sprintf("%c%c%c%c\n", last4[0], last4[1], last4[2], last4[3])
?
还有什么比这更好的了吗?我的代码看起来有点不合适。
答案 0 :(得分:3)
如果不是为了自我教育或类似的,你可能想要使用标准库中现有的RE parser,然后“走”AST来做任何需要的事情。
func Parse(s string, flags Flags) (*Regexp, error)
Parse解析由指定Flags控制的正则表达式字符串s, 并返回正则表达式解析树。语法在中描述 包regexp的顶级注释。
你的任务甚至还有helper。
EDIT1:您的代码已修复:
package main
import "fmt"
const sample string = `/(?P<country>m((a|b).+)(x|y)n)/(?P<city>.+)`
func main() {
extract(sample)
}
func extract(regex string) {
var last4 [4]int32
for _, c := range regex {
last4[0], last4[1], last4[2], last4[3] = last4[1], last4[2], last4[3], c
last4String := fmt.Sprintf("%c%c%c%c", last4[0], last4[1], last4[2], last4[3])
if last4String == "(?P<" {
fmt.Println("start of capturing group")
}
}
}
(还here)
EDIT2:您的代码被重写:
package main
import (
"fmt"
"strings"
)
const sample string = `/(?P<country>m((a|b).+)(x|y)n)/(?P<city>.+)`
func main() {
extract(sample)
}
func extract(regex string) {
start := 0
for {
i := strings.Index(regex[start:], "(?P<")
if i < 0 {
break
}
fmt.Printf("start of capturing group @ %d\n", start+i)
start += i + 1
}
}
(还here)