• golang中的正则表达式使用注意事项与技巧


    regexp模块

    查看帮助文档:

    命令行查看:go doc regexp/syntax

    在线查看:

    1. 中文文档 :
      菜鸟教程 介绍一些正则的方法比较详细
      GO语言中文文档对一些难懂的基础语法做了解释,比官方文档更易懂
    2. 英文文档:
      https://pkg.go.dev/regexp go标准库文档,有很多示例。

    关于转义字符的使用

    反引号中使用类似\w(\w代表0-9A-Za-z_)这样的语法不用做任何处理

    grep, _ := regexp.Compile(`\w{1,}`)
    
    • 1

    而在双引号中,反斜杠代表转义符。所以使用\w时,需要额外使用一个\将反斜杠转义为普通字符串,否则报错

    grep, _ := regexp.Compile("\\w{1,}")  
    
    • 1

    关于最多和最少匹配

    python中,最小匹配是有函数可以调用的。而go的regexp模块没有最小匹配的函数。
    如果要使用最小匹配,需要配合正则的语法,在文档中介绍在这里

    重复:
    
            x*             重复>=0次匹配x,越多越好(优先重复匹配x)
            x+             重复>=1次匹配x,越多越好(优先重复匹配x)
            x?             0或1次匹配x,优先1次
            x{n,m}         n到m次匹配x,越多越好(优先重复匹配x)
            x{n,}          重复>=n次匹配x,越多越好(优先重复匹配x)
            x{n}           重复n次匹配x
            x*?            重复>=0次匹配x,越少越好(优先跳出重复)
            x+?            重复>=1次匹配x,越少越好(优先跳出重复)
            x??            0或1次匹配x,优先0次
            x{n,m}?        n到m次匹配x,越少越好(优先跳出重复)
            x{n,}?         重复>=n次匹配x,越少越好(优先跳出重复)
            x{n}?          重复n次匹配x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上面的解释中,带有越少越好的就是最小匹配。*+稍有不慎就把全文都给你匹配出来

    str := `"老虎大王者荣耀超人"`                   //要查找的字符串  
    re := regexp.MustCompile("[\u4e00-\u9fa5]{1,3}") //匹配规则,匹配1到3个中文字符
    fmt.Println(re.FindAllString(str, -1)) //查询
    
    • 1
    • 2
    • 3

    输出

    [老虎大 王者荣 耀超人]
    
    • 1

    关于.*? 的坑

    在javaScript和python等其它语言中,.*?表示查询所有任意的字符串
    而在golang中,文档中是这样说明的

    x*?            重复>=0次匹配x,越少越好(优先跳出重复)
    
    • 1

    注意,重点在于匹配原则是内容越少越好,而正则表达式.*?中的.代表任意字符串(包括空字符串)。

    按照这种匹配原则,空字符串总是优先匹配到的,这样就导致了下面的问题:

    func TestFlag5(t *testing.T) {  
       data := "你吃饭了吗"  
       grep, _ := regexp.Compile(".*?")  
       result := grep.FindAllString(data, -1)  
       t.Log(result)  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出结果是

    structToJson_test.go:107: [     ]
    
    • 1

    它只匹配到了五个空字符串。

    解决方案有两种。第一种,把问号去掉,变成.*即可。 查看文档,(.*的匹配原则是越多越好)

    func TestFlag6(t *testing.T) {  
       data1 := "你吃饭了吗"  
       grep, _ := regexp.Compile(".*")//.*?改成了 .*  
       result := grep.FindAllString(data1, -1)  
       t.Log(result)  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    输出

    structToJson_test.go:107: [你吃饭了吗]
    
    • 1

    第二种方案,.*?后面必须包含字符串

    func TestFlag7(t *testing.T) {    
       str := `你吃饭了吗`                      //要查找的字符串  
       re, _ := regexp.Compile(".*?了吗")      //.*?后面加几个字符串,开头加不加无所谓  
       t.Log(re.FindAllString(str, -1)) //查询
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出

    [你吃饭了吗]
    
    • 1

    关于匹配中文字符的坑

    匹配中文字符这里有个坑,如果匹配规则使用的是双引号,正常输入匹配规则即可

    re := regexp.MustCompile("[\u4e00-\u9fa5]{1,}")//匹配规则,\u4e00-\u9fa5表示unicoce中的人一个中文字符
    
    • 1

    但是如果你使用反引号包裹上面的匹配规则,查询时会导致panic报错

    re := regexp.MustCompile(`[\u4e00-\u9fa5]{1,}`)//错误示例
    
    • 1

    需要写一个双引号包裹的匹配规则,然后赋值粘贴进去,最后变成一串乱码,这才是正确的。

    re := regexp.MustCompile(`[一-龥]{1,}`) //匹配规则
    
    • 1

    基础查询函数的说明

    常用的查询方法

    1. FindAllString: 完整匹配,仅查询一次,查询到后就返回;
    2. FindString: 完整匹配,可指定查询数量(全部或多个);
    3. FindStringSubmatch :子项查询,获取查询条件中指定的内容。仅查询一次,查询到后就返回;
    4. FindAllStringSubmatch: 子项查询,获取查询条件中指定的内容。可指定查询数量(全部或多个)。

    子项查询 FindStringSubmatch

    注意点:

    1. 使用英文括号包裹需正则中需要获取的内容
    2. 这里使用FindStringSubmatch方法进行搜索。仅查询一次。
    func TestFlag5(t *testing.T) {  
       str := `_A_123567abv`                    //要查找的字符串  
       re, _ := regexp.Compile("_\\w_(.*)") //匹配规则  
       fmt.Println(re.FindStringSubmatch(str))  //查询  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    输出:

    [_A_123567abv 123567abv]
    
    • 1

    搜索结果中,第一个是正则中完全匹配到的内容。第二个开始才是想要获取的子项。

    子项查询 FindAllStringSubmatch

    分组查询时,在正则表达式中,将需要查询出来的内容用()括起来。

    //查询内容
    data1 := "type Demo struct {
    	Name string `json:\"name\" form:\"name\" gorm:\"column:name;comment: \"`
    	Age  int    `json:\"age\" form:\"age\" gorm:\"column:age;comment: \"`
    	}"
    	
    //正则表达式:查询结构体字段、字段类型和json标签中的内容
    grep, _ := regexp.Compile(`([\w]{1,})[ ]{1,}([\[\]\w]{2,})[ ]{1,}` + "`" + `(json):"([\w]{1,})[,]{0,}(\w{0,})\"` + ".*`")  
    
    //使用FindAllStringSubmatch函数查询
    result := grep.FindAllStringSubmatch(*s.StructValue, -1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输出结果:

    [
    [Name string `json:"name" form:"name" gorm:"column:name;comment: "` Name string json name ] [Age  int    `json:"age" form:"age" gorm:"column:age;comment: "` Age int json age ]
    ]
    
    • 1
    • 2
    • 3

    注意,在这里,每个匹配的搜索结果都单独放在一个切片中。

  • 相关阅读:
    SpringMVC 启动流程源码分析
    docker开机启动设置
    2023-油猴(Tampermonkey)脚本推荐
    JavaWeb-JSTL标签库
    C#基于BytesIO程序包的TCP Client客户端窗体程序
    2023.11.19 hadoop之MapReduce
    【Computer Composition】Part1 计算机系统概述
    【C++类型转换】4种类型转换:static_cast、reinterpret_cast、const_cast、dynamic_cast
    AN动画基础——摄像头
    后端接口性能优化分析-程序结构优化
  • 原文地址:https://blog.csdn.net/dorlolo/article/details/125457787