Golang中正则表达式的正确使用方法

Golang中正则表达式的正确使用方法 我正在尝试使用正则表达式解析 ps 命令的输出,但目前无法正常工作。调用 ps 命令时使用了以下参数:

$  ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt

示例输出如下:

343      0  0.0  0.0  3936 R    ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt

以下是我正在使用的正则表达式:

/^(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)$/gm

代码如下:

pattern := /^(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)$/gm
regex, _ := regexp.Compile(pattern)
match := regex.FindStringSubmatch(ps_line_str)

但没有任何匹配项。请注意,该正则表达式模式在 https://regex101.com 上的“Regular Expressions 101”工具中有效,并提供以下匹配信息:

Match 1   0-93  343      0  0.0  0.0  3936 R    ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt
Group 1   0-3    343
Group 2   9-10   0
Group 3   12-15  0.0
Group 4   17-20  0.0
Group 5   22-26  3936
Group 6   27-28  R
Group 7   32-34  ps 
Group 8   35-93  -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt

还有一点信息,当正则表达式减少四个捕获组并且 ps 命令按如下方式调用时,它工作正常:

$ ps -eo min_flt,maj_flt,%mem,cmd --sort=-maj_flt

输出看起来像这样:

1154      0  0.0 ps -eo min_flt,maj_flt,%mem,cmd --sort=-maj_flt

代码像这样:

pattern := `^(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)$`
regex, _ := regexp.Compile(pattern)
match := regex.FindStringSubmatch(ps_line_str)

并且匹配会成功找到所有分组。

非常感谢任何帮助。

此致。


更多关于Golang中正则表达式的正确使用方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我发帖太早了,因为我刚刚在 https://regex101.com 网站上找到了答案。他们有一个侧边栏菜单“Flavors”,你可以在那里选择你正在使用的语言。当我将其更改为 Golang 时,正则表达式被更改如下:

^(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)[\s]+(.*?)$

现在代码又可以正常工作了。我发布这个后续信息,以防有人遇到类似的问题。

谢谢。

更多关于Golang中正则表达式的正确使用方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中使用正则表达式时,有几个关键点需要注意。你的正则表达式在regex101上有效但在Go中失败,主要是因为Go的regexp包不支持/gm修饰符和某些正则语法。

以下是修正后的代码:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    ps_line_str := "343      0  0.0  0.0  3936 R    ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt"
    
    // 修正后的正则表达式
    pattern := `^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$`
    
    regex, err := regexp.Compile(pattern)
    if err != nil {
        panic(err)
    }
    
    match := regex.FindStringSubmatch(ps_line_str)
    if match != nil {
        fmt.Printf("完整匹配: %s\n", match[0])
        for i := 1; i < len(match); i++ {
            fmt.Printf("Group %d: %s\n", i, match[i])
        }
    } else {
        fmt.Println("没有匹配")
    }
}

输出结果:

完整匹配: 343      0  0.0  0.0  3936 R    ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt
Group 1: 343
Group 2: 0
Group 3: 0.0
Group 4: 0.0
Group 5: 3936
Group 6: R
Group 7: ps -eo min_flt,maj_flt,%cpu,%mem,rss,stat,cmd --sort=-maj_flt

主要修正点:

  1. 移除修饰符:Go的regexp包不支持/gm修饰符,这些需要在模式中明确表示
  2. 使用原始字符串:使用反引号`而不是斜杠/
  3. 简化模式:使用\S+匹配非空白字符,\s+匹配空白字符
  4. 处理命令部分:最后一个捕获组使用.+匹配剩余的所有内容

如果你需要更灵活地处理可变数量的空格,可以使用这个模式:

pattern := `^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$`

或者使用更通用的方法处理ps输出:

func parsePSOutput(line string) map[string]string {
    pattern := `^(\d+)\s+(\d+)\s+([\d.]+)\s+([\d.]+)\s+(\d+)\s+(\S+)\s+(.+)$`
    regex := regexp.MustCompile(pattern)
    
    match := regex.FindStringSubmatch(line)
    if match == nil {
        return nil
    }
    
    return map[string]string{
        "min_flt":  match[1],
        "maj_flt":  match[2],
        "cpu":      match[3],
        "mem":      match[4],
        "rss":      match[5],
        "stat":     match[6],
        "cmd":      match[7],
    }
}

对于错误处理,建议总是检查Compile的返回值:

regex, err := regexp.Compile(pattern)
if err != nil {
    // 处理错误
    log.Fatalf("无效的正则表达式: %v", err)
}

Go的regexp包使用RE2引擎,不支持一些PCRE特性如回溯引用、前向断言等,但性能更好且保证线性时间匹配。

回到顶部