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

5 回复

你能提供一些示例输入文本和期望的输出文本吗?

更多关于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()返回的是匹配的起始和结束位置切片,避免了重复的正则表达式匹配操作。

回到顶部