Golang中使用regex.Split如何保留分隔符
Golang中使用regex.Split如何保留分隔符
你好,
我正在使用正则表达式分割文本部分,但问题是 reg.Split 会移除分隔符。
有没有比下面这种方法更好(更高效)的方式来保留分隔符呢?
reg := regexp.MustCompile(`(?m)^\[\d+:\d+:\d+]`)
split := reg.Split(string(log), -1)
var test []string
for index, line := range split {
submatch := reg.FindAllStringSubmatch(string(log), -1)
submatch2 := submatch[index][0]
test = append(test, submatch2 + line)
}
因为如果我没理解错的话,它执行了两次“正则匹配”,这很不好,因为我需要它尽可能快。
更多关于Golang中使用regex.Split如何保留分隔符的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你能提供一些示例输入文本和期望的输出文本吗?
更多关于Golang中使用regex.Split如何保留分隔符的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
以下是代码示例:Go Playground - The Go Programming Language
期望的输出是“[HH:mm:ss] something[num]”,而不仅仅是“something[num]”
你之所以只得到“something[num]”,是因为你使用了 (*Regexp).Split,它会查找你指定的模式,并在每次找到该文本时分割字符串,就像 strings.Split 一样。你说你想要“[HH:mm:ss] something[num]”,但源文本已经是这种格式了,那么为什么还要解析它,只是为了把它重新放回那种格式呢?
@abcdef - 那么你的输入是按行进入的——
[01:00:00] something1
[02:00:00] something2
[03:00:00] something3
[04:00:00] something4
——并且想把每一行放入一个切片字段中?
如果你在正则表达式中包含行的其余部分(.*$)并使用 FindAllString 而不是 Split(Playground),你会得到一个 [HH:mm:ss] something[num] 值的切片。
[[01:00:00] something1 [02:00:00] something2 [03:00:00] something3 [04:00:00] something4]
这是你想要的输出吗?
在Go中,regexp.Split()确实会移除分隔符。要保留分隔符,更高效的方法是使用FindAllString()配合FindAllStringIndex()。以下是优化后的实现:
package main
import (
"fmt"
"regexp"
)
func splitWithDelimiters(text string, re *regexp.Regexp) []string {
var result []string
lastIndex := 0
// 获取所有匹配的位置
matches := re.FindAllStringIndex(text, -1)
for _, match := range matches {
start, end := match[0], match[1]
// 添加非匹配部分
if start > lastIndex {
result = append(result, text[lastIndex:start])
}
// 添加分隔符
result = append(result, text[start:end])
lastIndex = end
}
// 添加最后剩余部分
if lastIndex < len(text) {
result = append(result, text[lastIndex:])
}
return result
}
func main() {
log := `[0:0:0] First log entry
[1:2:3] Second log entry
[4:5:6] Third log entry`
reg := regexp.MustCompile(`(?m)^\[\d+:\d+:\d+\]`)
// 使用优化后的函数
parts := splitWithDelimiters(log, reg)
for i, part := range parts {
fmt.Printf("Part %d: %q\n", i, part)
}
}
或者使用FindAllStringSubmatchIndex()获取更详细的匹配信息:
func splitWithDelimitersV2(text string, re *regexp.Regexp) []string {
var result []string
lastIndex := 0
// 获取所有匹配及其子匹配的位置
matches := re.FindAllStringSubmatchIndex(text, -1)
for _, match := range matches {
start, end := match[0], match[1]
// 添加非匹配部分
if start > lastIndex {
result = append(result, text[lastIndex:start])
}
// 添加分隔符
result = append(result, text[start:end])
lastIndex = end
}
// 添加最后剩余部分
if lastIndex < len(text) {
result = append(result, text[lastIndex:])
}
return result
}
对于你的具体用例,可以这样处理日志分割:
func splitLogWithTimestamps(log string) []string {
reg := regexp.MustCompile(`(?m)^\[\d+:\d+:\d+\]`)
var logs []string
lastIndex := 0
matches := reg.FindAllStringIndex(log, -1)
for i, match := range matches {
start, end := match[0], match[1]
// 确定当前日志条目的结束位置
nextStart := len(log)
if i+1 < len(matches) {
nextStart = matches[i+1][0]
}
// 组合时间戳和日志内容
logEntry := log[start:nextStart]
logs = append(logs, logEntry)
lastIndex = end
}
return logs
}
这些方法都只执行一次正则匹配,比原始方案更高效。FindAllStringIndex()返回的是匹配的起始和结束位置切片,避免了重复的正则表达式匹配操作。

