Golang如何使用正则表达式实现字符串部分匹配
Golang如何使用正则表达式实现字符串部分匹配 假设LLM将生成如下完整文本:
Larson graduated from Webster^[1][2]^ and Tooele^[3]^...
我的程序可能接收到的输出序列是:
- Larson
- graduated from
- Webster^
- [
- 1][2
- ]^ and
- Tooele
- ^[
- 3
- ]^
- …
我希望在收到字符串时,能立即根据正则表达式 \^(\[\d+])+\^ 过滤掉所有引用。
处理流程如下:

最终输出:
Larson graduated from Webster and Tooele...
问题是如何像 Webster^、Webster^1][2 这样,对字符串进行部分匹配的正则表达式?
注意:
不要手动枚举所有正则表达式,例如:
\^$|\^\[$|\^\[\d+$|\^(\[\d+])+$|\^(\[\d+])*\[$|\^(\[\d+])*\[\d+$
这种方式容易出错且难以维护。
更多关于Golang如何使用正则表达式实现字符串部分匹配的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于Golang如何使用正则表达式实现字符串部分匹配的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Go中处理流式数据时,可以使用正则表达式的FindReaderIndex方法配合io.RuneReader来实现部分匹配。以下是实现方案:
package main
import (
"bufio"
"fmt"
"io"
"regexp"
"strings"
)
type CitationFilter struct {
re *regexp.Regexp
buffer []rune
inMatch bool
matchBuf []rune
}
func NewCitationFilter() *CitationFilter {
return &CitationFilter{
re: regexp.MustCompile(`\^(\[\d+])+\^`),
}
}
func (cf *CitationFilter) ProcessChunk(chunk string) string {
cf.buffer = append(cf.buffer, []rune(chunk)...)
var result strings.Builder
for len(cf.buffer) > 0 {
if cf.inMatch {
// 正在匹配引用标记中
cf.matchBuf = append(cf.matchBuf, cf.buffer[0])
cf.buffer = cf.buffer[1:]
// 尝试匹配完整模式
if cf.re.MatchString(string(cf.matchBuf)) {
cf.inMatch = false
cf.matchBuf = nil
} else if !couldBePartial(cf.matchBuf) {
// 不可能是部分匹配,输出缓冲内容
result.WriteString(string(cf.matchBuf))
cf.inMatch = false
cf.matchBuf = nil
}
} else {
// 查找可能的引用开始
start := -1
for i, r := range cf.buffer {
if r == '^' {
start = i
break
}
}
if start == -1 {
// 没有找到^,输出全部
result.WriteString(string(cf.buffer))
cf.buffer = nil
} else {
// 输出^之前的内容
if start > 0 {
result.WriteString(string(cf.buffer[:start]))
}
// 开始匹配
cf.inMatch = true
cf.matchBuf = []rune{cf.buffer[start]}
cf.buffer = cf.buffer[start+1:]
}
}
}
return result.String()
}
func couldBePartial(buf []rune) bool {
str := string(buf)
// 检查是否可能是部分匹配的模式
if !strings.HasPrefix(str, "^") {
return false
}
// 允许的模式:^, ^[, ^[数字, ^[数字], ^[数字][, 等
re := regexp.MustCompile(`^\^(\[\d+\])*(\[\d+)?(\[)?$`)
return re.MatchString(str)
}
// 使用示例
func main() {
filter := NewCitationFilter()
chunks := []string{
"Larson ",
"graduated from ",
"Webster^",
"[",
"1][2",
"]^ and ",
"Tooele",
"^[",
"3",
"]^",
"...",
}
var output strings.Builder
for _, chunk := range chunks {
processed := filter.ProcessChunk(chunk)
output.WriteString(processed)
}
// 处理剩余的缓冲
if len(filter.buffer) > 0 {
output.WriteString(string(filter.buffer))
}
fmt.Println("Final output:", output.String())
// 输出: Larson graduated from Webster and Tooele...
}
更简洁的方案是使用regexp.Regexp的FindReaderIndex:
package main
import (
"bytes"
"fmt"
"regexp"
"strings"
)
type StreamingFilter struct {
re *regexp.Regexp
buffer bytes.Buffer
}
func NewStreamingFilter() *StreamingFilter {
return &StreamingFilter{
re: regexp.MustCompile(`\^(\[\d+])+\^`),
}
}
func (sf *StreamingFilter) ProcessChunk(chunk string) string {
sf.buffer.WriteString(chunk)
data := sf.buffer.Bytes()
// 查找所有完整匹配
matches := sf.re.FindAllIndex(data, -1)
if matches == nil {
return chunk
}
var result strings.Builder
lastEnd := 0
for _, match := range matches {
// 输出匹配之前的内容
result.Write(data[lastEnd:match[0]])
lastEnd = match[1]
}
// 输出剩余内容
result.Write(data[lastEnd:])
// 更新缓冲区
sf.buffer.Reset()
sf.buffer.Write(result.Bytes())
return result.String()
}
func main() {
filter := NewStreamingFilter()
testCases := []struct {
input string
expected string
}{
{"Webster^", "Webster"},
{"[1][2", ""},
{"]^ and", " and"},
{"Tooele^[", "Tooele"},
{"3]^...", "..."},
}
for _, tc := range testCases {
output := filter.ProcessChunk(tc.input)
fmt.Printf("Input: %q -> Output: %q\n", tc.input, output)
}
}
对于更复杂的流式处理,可以使用状态机:
package main
import (
"fmt"
"strings"
)
type CitationState int
const (
StateText CitationState = iota
StateStartCite // 遇到^
StateInBracket // 遇到[
StateInNumber // 在数字中
StateEndBracket // 遇到]
StateEndCite // 遇到结束^
)
type CitationParser struct {
state CitationState
buffer strings.Builder
citeBuf strings.Builder
}
func (cp *CitationParser) ProcessRune(r rune) string {
switch cp.state {
case StateText:
if r == '^' {
cp.state = StateStartCite
cp.citeBuf.WriteRune(r)
return ""
}
cp.buffer.WriteRune(r)
return ""
case StateStartCite:
cp.citeBuf.WriteRune(r)
if r == '[' {
cp.state = StateInBracket
} else {
// 无效格式,回退到文本状态
cp.buffer.WriteString(cp.citeBuf.String())
cp.citeBuf.Reset()
cp.state = StateText
}
return ""
case StateInBracket:
cp.citeBuf.WriteRune(r)
if r >= '0' && r <= '9' {
cp.state = StateInNumber
} else {
// 无效格式
cp.buffer.WriteString(cp.citeBuf.String())
cp.citeBuf.Reset()
cp.state = StateText
}
return ""
case StateInNumber:
cp.citeBuf.WriteRune(r)
if r == ']' {
cp.state = StateEndBracket
} else if r < '0' || r > '9' {
// 无效格式
cp.buffer.WriteString(cp.citeBuf.String())
cp.citeBuf.Reset()
cp.state = StateText
}
return ""
case StateEndBracket:
cp.citeBuf.WriteRune(r)
if r == '^' {
cp.state = StateEndCite
cp.citeBuf.Reset()
cp.state = StateText
return ""
} else if r == '[' {
cp.state = StateInBracket
} else {
// 无效格式
cp.buffer.WriteString(cp.citeBuf.String())
cp.citeBuf.Reset()
cp.state = StateText
}
return ""
case StateEndCite:
// 不应该到达这里
cp.state = StateText
return ""
}
return ""
}
func (cp *CitationParser) Flush() string {
result := cp.buffer.String()
if cp.citeBuf.Len() > 0 {
result += cp.citeBuf.String()
}
cp.buffer.Reset()
cp.citeBuf.Reset()
cp.state = StateText
return result
}
func main() {
parser := &CitationParser{}
input := "Webster^[1][2]^ and Tooele^[3]^"
for _, r := range input {
parser.ProcessRune(r)
}
result := parser.Flush()
fmt.Println("Result:", result) // 输出: Webster and Tooele
}

