基础知识 - Golang 中的正则表达式

元字符:

表1.常用的元字符
代码说明
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
 
   

字符转义:

如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用\.和\*。当然,要查找\本身,你也得用\\.

例如:deerchao\.net匹配deerchao.net,C:\\Windows匹配C:\Windows

重复:

你已经看过了前面的*,+,{2},{5,12}这几个匹配重复的方式了。下面是正则表达式中所有的限定符(指定数量的代码,例如*,{5,12}等):

表2.常用的限定符
代码/语法说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

下面是一些使用重复的例子:

Windows\d+匹配Windows后面跟1个或更多数字

^\w+匹配一行的第一个单词(或整个字符串的第一个单词,具体匹配哪个意思得看选项设置)

字符类:

要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符,但是如果你想匹配没有预定义元字符的字符集合(比如元音字母a,e,i,o,u),应该怎么办?

很简单,你只需要在方括号里列出它们就行了,像[aeiou]就匹配任何一个英文元音字母,[.?!]匹配标点符号(.或?或!)。

我们也可以轻松地指定一个字符范围,像[0-9]代表的含意与\d就是完全一致的:一位数字;同理[a-z0-9A-Z_]也完全等同于\w(如果只考虑英文的话)。

下面是一个更复杂的表达式:\(?0\d{2}[) -]?\d{8}。

“(”和“)”也是元字符,后面的分组节里会提到,所以在这里需要使用转义

这个表达式可以匹配几种格式的电话号码,像(010)88886666,或022-22334455,或02912345678等。我们对它进行一些分析吧:首先是一个转义字符\(,它能出现0次或1次(?),然后是一个0,后面跟着2个数字(\d{2}),然后是)或-或空格中的一个,它出现1次或不出现(?),最后是8个数字(\d{8})。

分枝条件:

不幸的是,刚才那个表达式也能匹配010)12345678或(022-87654321这样的“不正确”的格式。要解决这个问题,我们需要用到分枝条件。正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。听不明白?没关系,看例子:

0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。

\(?0\d{2}\)?[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。

\d{5}-\d{4}|\d{5}这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。

分组

我们已经提到了怎么重复单个字符(直接在字符后面加上限定符就行了);但如果想要重复多个字符又该怎么办?你可以用小括号来指定子表达式(也叫做分组),然后你就可以指定这个子表达式的重复次数了,你也可以对子表达式进行其它一些操作(后面会有介绍)。

(\d{1,3}\.){3}\d{1,3}是一个简单的IP地址匹配表达式。要理解这个表达式,请按下列顺序分析它:\d{1,3}匹配1到3位的数字,(\d{1,3}\.){3}匹配三位数字加上一个英文句号(这个整体也就是这个分组)重复3次,最后再加上一个一到三位的数字(\d{1,3})。

IP地址中每个数字都不能大于255. 经常有人问我, 01.02.03.04 这样前面带有0的数字, 是不是正确的IP地址呢? 答案是: 是的, IP 地址里的数字可以包含有前导 0 (leading zeroes).

不幸的是,它也将匹配256.300.888.999这种不可能存在的IP地址。如果能使用算术比较的话,或许能简单地解决这个问题,但是正则表达式中并不提供关于数学的任何功能,所以只能使用冗长的分组,选择,字符类来描述一个正确的IP地址:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。

理解这个表达式的关键是理解2[0-4]\d|25[0-5]|[01]?\d\d?,这里我就不细说了,你自己应该能分析得出来它的意义。

反义

有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:

表3.常用的反义代码
代码/语法说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

例子:\S+匹配不包含空白符的字符串。

<a[^>]+>匹配用尖括号括起来的以a开头的字符串。

后向引用

使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。

呃……其实,组号分配还不像我刚说得那么简单:

  • 分组0对应整个正则表达式
  • 实际上组号分配过程是要从左向右扫描两遍的:第一遍只给未命名组分配,第二遍只给命名组分配--因此所有命名组的组号都大于未命名的组号
  • 你可以使用(?:exp)这样的语法来剥夺一个分组对组号分配的参与权.

后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:

\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。

你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b。

使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:

表4.常用分组语法
分类代码/语法说明
捕获 (exp) 匹配exp,并捕获文本到自动命名的组里
(?<name>exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
零宽断言 (?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(?<!exp) 匹配前面不是exp的位置
注释 (?#comment) 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读

我们已经讨论了前两种语法。第三个(?:exp)不会改变正则表达式的处理方式,只是这样的组匹配的内容不会像前两种那样被捕获到某个组里面,也不会拥有组号。“我为什么会想要这样做?”——好问题,你觉得为什么呢?

零宽断言

地球人,是不是觉得这些术语名称太复杂,太难记了?我也有同感。知道有这么一种东西就行了,它叫什么,随它去吧!人若无名,便可专心练剑;物若无名,便可随意取舍……

接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。最好还是拿例子来说明吧:

断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。

(?=exp)也叫零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b),匹配以ing结尾的单词的前面部分(除了ing以外的部分),如查找I'm singing while you're dancing.时,它会匹配sing和danc。

(?<=exp)也叫零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式exp。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分(除了re以外的部分),例如在查找reading a book时,它匹配ading。

假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})+\b,用它对1234567890进行查找时结果是234567890。

下面这个例子同时使用了这两种断言:(?<=\s)\d+(?=\s)匹配以空白符间隔的数字(再次强调,不包括这些空白符)。

负向零宽断言

前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样:

\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。

零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。

同理,我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。

请详细分析表达式(?<=<(\w+)>).*(?=<\/\1>),这个表达式最能表现零宽断言的真正用途。

一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。(?<=<(\w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)。

注释

小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。

要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:

      (?<=    # 断言要匹配的文本的前缀
      <(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签)
      )       # 前缀结束
      .*      # 匹配任意文本
      (?=     # 断言要匹配的文本的后缀
      <\/\1>  # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签
      )       # 后缀结束

golang 实现
package lib

import (
    "regexp"
)
 
func IsEmail(email string) bool {
    if email != "" {
        if isOk, _ := regexp.MatchString("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4})$", email); isOk {
            return true
        }
    }

    return false
}
 
func IsPhone(phoneStr string) bool {
    if phoneStr != "" {
        if isOk, _ := regexp.MatchString(`^\([\d]{3}\) [\d]{3}-[\d]{4}$`, phoneStr); isOk {
            return isOk
        }
    }

    return false
}

 

 




1 数字:^[0-9]*$
2 n位的数字:^\d{n}$
3 至少n位的数字:^\d{n,}$
4 m-n位的数字:^\d{m,n}$
5 零和非零开头的数字:^(0|[1-9][0-9]*)$
6 非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(.[0-9]{1,2})?$
7 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})?$
8 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
9 有两位小数的正实数:^[0-9]+(.[0-9]{2})?$
10 有1~3位小数的正实数:^[0-9]+(.[0-9]{1,3})?$
11 非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
12 非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13 非负整数:^\d+$ 或 ^[1-9]\d*|0$
14 非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
15 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17 正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18 负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$



二、校验字符的表达式
1 汉字:^[\u4e00-\u9fa5]{0,}$
2 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
3 长度为3-20的所有字符:^.{3,20}$
4 由26个英文字母组成的字符串:^[A-Za-z]+$
5 由26个大写英文字母组成的字符串:^[A-Z]+$
6 由26个小写英文字母组成的字符串:^[a-z]+$
7 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
8 由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
9 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
10 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$ 或 ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11 可以输入含有^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12 禁止输入含有~的字符:[^~\x22]+

三、特殊需求表达式
1 Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3 InternetURL:[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5 电话号码("XXX-XXXXXXX"、"XXXX-XXXXXXXX"、"XXX-XXXXXXX"、"XXX-XXXXXXXX"、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
7 身份证号(15位、18位数字):^\d{15}|\d{18}$
8 短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
11 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12 日期格式:^\d{4}-\d{1,2}-\d{1,2}
13 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
14 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
15 钱的输入格式:
16 1.有四种钱的表示形式我们可以接受:"10000.00" 和 "10,000.00", 和没有 "分" 的 "10000" 和 "10,000":^[1-9][0-9]*$
17 2.这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
18 3.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
19 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧.下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
20 5.必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 "10" 和 "10.2" 是通过的:^[0-9]+(.[0-9]{2})?$
21 6.这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
22 7.这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
23 8.1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
24 备注:这就是最终结果了,别忘了"+"可以用"*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
25 xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26 中文字符的正则表达式:[\u4e00-\u9fa5]
27 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
28 空白行的正则表达式:\n\s*\r (可以用来删除空白行)
29 HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> (网上流传的版本太糟糕,上面这个也仅仅能部分,对于复杂的嵌套标记依旧无能为力)
30 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
31 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
32 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
33 IP地址:\d+\.\d+\.\d+\.\d+ (提取IP地址时有用)
34 IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))   








package main

import (
    "regexp"
)

const (
    regular = "^(13[0-9]|14[57]|15[0-35-9]|18[07-9])\\\\d{8}$"
)

func validate(mobileNum string) bool {
    reg := regexp.MustCompile(regular)
    return reg.MatchString(mobileNum)
}

func main() {
    if validate("13888888888") {
        println("是手机号")
        return
    }

    println("不是手机号")
}
//该片段来自

  

 




------------------------------------------------------------ Golang中的正则表达式 ------------------------------------------------------------ 用法: ------------------------------ 单一:     .        匹配任意一个字符,如果设置 s = true,则可以匹配换行符     [字符类]      匹配“字符类”中的一个字符,“字符类”见后面的说明     [^字符类]    匹配“字符类”外的一个字符,“字符类”见后面的说明     \小写Perl标记  匹配“Perl类”中的一个字符,“Perl类”见后面的说明     \大写Perl标记  匹配“Perl类”外的一个字符,“Perl类”见后面的说明     [:ASCII类名:]  匹配“ASCII类”中的一个字符,“ASCII类”见后面的说明     [:^ASCII类名:]  匹配“ASCII类”外的一个字符,“ASCII类”见后面的说明     \pUnicode普通类名 匹配“Unicode类”中的一个字符(仅普通类),“Unicode类”见后面的说明     \PUnicode普通类名 匹配“Unicode类”外的一个字符(仅普通类),“Unicode类”见后面的说明     \p{Unicode类名}  匹配“Unicode类”中的一个字符,“Unicode类”见后面的说明     \P{Unicode类名}  匹配“Unicode类”外的一个字符,“Unicode类”见后面的说明 ------------------------------ 复合:     xy      匹配 xy(x 后面跟随 y)     x|y      匹配 x 或 y (优先匹配 x) ------------------------------ 重复:     x*      匹配零个或多个 x,优先匹配更多(贪婪)     x+      匹配一个或多个 x,优先匹配更多(贪婪)     x?      匹配零个或一个 x,优先匹配一个(贪婪)     x{n,m}    匹配 n 到 m 个 x,优先匹配更多(贪婪)     x{n,}    匹配 n 个或多个 x,优先匹配更多(贪婪)     x{n}    只匹配 n 个 x     x*?      匹配零个或多个 x,优先匹配更少(非贪婪)     x+?      匹配一个或多个 x,优先匹配更少(非贪婪)     x??      匹配零个或一个 x,优先匹配零个(非贪婪)     x{n,m}?    匹配 n 到 m 个 x,优先匹配更少(非贪婪)     x{n,}?    匹配 n 个或多个 x,优先匹配更少(非贪婪)     x{n}?    只匹配 n 个 x ------------------------------ 分组:     (子表达式)      被捕获的组,该组被编号 (子匹配)     (?P<命名>子表达式)  被捕获的组,该组被编号且被命名 (子匹配)     (?:子表达式)    非捕获的组 (子匹配)     (?标记)      在组内设置标记,非捕获,标记影响当前组后的正则表达式     (?标记:子表达式)  在组内设置标记,非捕获,标记影响当前组内的子表达式     标记的语法是:     xyz (设置 xyz 标记)     -xyz (清除 xyz 标记)     xy-z (设置 xy 标记, 清除 z 标记)     可以设置的标记有:     i      不区分大小写 (默认为 false)     m      多行模式:让 ^ 和 $ 匹配整个文本的开头和结尾,而非行首和行尾(默认为 false)     s      让 . 匹配 \n (默认为 false)     U      非贪婪模式:交换 x* 和 x*? 等的含义 (默认为 false) ------------------------------ 位置标记:     ^      如果标记 m=true 则匹配行首,否则匹配整个文本的开头(m 默认为 false)     $      如果标记 m=true 则匹配行尾,否则匹配整个文本的结尾(m 默认为 false)     \A      匹配整个文本的开头,忽略 m 标记     \b      匹配单词边界     \B      匹配非单词边界     \z      匹配整个文本的结尾,忽略 m 标记 ------------------------------ 转义序列:     \a      匹配响铃符  (相当于 \x07)           注意:正则表达式中不能使用 \b 匹配退格符,因为 \b 被用来匹配单词边界,           可以使用 \x08 表示退格符。     \f      匹配换页符  (相当于 \x0C)     \t      匹配横向制表符(相当于 \x09)     \n      匹配换行符  (相当于 \x0A)     \r      匹配回车符  (相当于 \x0D)     \v      匹配纵向制表符(相当于 \x0B)     \123    匹配 8 進制编码所代表的字符(必须是 3 位数字)     \x7F    匹配 16 進制编码所代表的字符(必须是 3 位数字)     \x{10FFFF}  匹配 16 進制编码所代表的字符(最大值 10FFFF )     \Q...\E    匹配 \Q 和 \E 之间的文本,忽略文本中的正则语法     \\      匹配字符 \     \^      匹配字符 ^     \$      匹配字符 $     \.      匹配字符 .     \*      匹配字符 *     \+      匹配字符 +     \?      匹配字符 ?     \{      匹配字符 {     \}      匹配字符 }     \(      匹配字符 (     \)      匹配字符 )     \[      匹配字符 [     \]      匹配字符 ]     \|      匹配字符 | ------------------------------ 可以将“命名字符类”作为“字符类”的元素:     [\d]    匹配数字 (相当于 \d)     [^\d]    匹配非数字 (相当于 \D)     [\D]    匹配非数字 (相当于 \D)     [^\D]    匹配数字 (相当于 \d)     [[:name:]]  命名的“ASCII 类”包含在“字符类”中 (相当于 [:name:])     [^[:name:]]  命名的“ASCII 类”不包含在“字符类”中 (相当于 [:^name:])     [\p{Name}]  命名的“Unicode 类”包含在“字符类”中 (相当于 \p{Name})     [^\p{Name}]  命名的“Unicode 类”不包含在“字符类”中 (相当于 \P{Name}) ------------------------------------------------------------ 说明: ------------------------------ “字符类”取值如下(“字符类”包含“Perl类”、“ASCII类”、“Unicode类”):   x          单个字符   A-Z        字符范围(包含首尾字符)   \小写字母      Perl类   [:ASCII类名:]    ASCII类   \p{Unicode脚本类名} Unicode类 (脚本类)   \pUnicode普通类名  Unicode类 (普通类) ------------------------------ “Perl 类”取值如下:   \d      数字 (相当于 [0-9])   \D      非数字 (相当于 [^0-9])   \s      空白 (相当于 [\t\n\f\r ])   \S      非空白 (相当于[^\t\n\f\r ])   \w      单词字符 (相当于 [0-9A-Za-z_])   \W      非单词字符 (相当于 [^0-9A-Za-z_]) ------------------------------ “ASCII 类”取值如下   [:alnum:]  字母数字 (相当于 [0-9A-Za-z])   [:alpha:]  字母 (相当于 [A-Za-z])   [:ascii:]  ASCII 字符集 (相当于 [\x00-\x7F])   [:blank:]  空白占位符 (相当于 [\t ])   [:cntrl:]  控制字符 (相当于 [\x00-\x1F\x7F])   [:digit:]  数字 (相当于 [0-9])   [:graph:]  图形字符 (相当于 [!-~])   [:lower:]  小写字母 (相当于 [a-z])   [:print:]  可打印字符 (相当于 [ -~] 相当于 [ [:graph:]])   [:punct:]  标点符号 (相当于 [!-/:-@[-反引号{-~])   [:space:]  空白字符(相当于 [\t\n\v\f\r ])   [:upper:]  大写字母(相当于 [A-Z])   [:word:]  单词字符(相当于 [0-9A-Za-z_])   [:xdigit:]  16 進制字符集(相当于 [0-9A-Fa-f]) ------------------------------ “Unicode 类”取值如下---普通类:   C        -其他-    (other)   Cc        控制字符    (control)   Cf        格式      (format)   Co        私人使用区  (private use)   Cs        代理区    (surrogate)   L        -字母-    (letter)   Ll        小写字母    (lowercase letter)   Lm        修饰字母    (modifier letter)   Lo        其它字母    (other letter)   Lt        首字母大写字母 (titlecase letter)   Lu        大写字母    (uppercase letter)   M        -标记-    (mark)   Mc        间距标记    (spacing mark)   Me        关闭标记    (enclosing mark)   Mn        非间距标记  (non-spacing mark)   N        -数字-    (number)   Nd        十進制数字  (decimal number)   Nl        字母数字    (letter number)   No        其它数字    (other number)   P        -标点-    (punctuation)   Pc        连接符标点  (connector punctuation)   Pd        破折号标点符号 (dash punctuation)   Pe        关闭的标点符号 (close punctuation)   Pf        最后的标点符号 (final punctuation)   Pi        最初的标点符号 (initial punctuation)   Po        其他标点符号  (other punctuation)   Ps        开放的标点符号 (open punctuation)   S        -符号-    (symbol)   Sc        货币符号    (currency symbol)   Sk        修饰符号    (modifier symbol)   Sm        数学符号    (math symbol)   So        其他符号    (other symbol)   Z        -分隔符-    (separator)   Zl        行分隔符    (line separator)   Zp        段落分隔符  (paragraph separator)   Zs        空白分隔符  (space separator) ------------------------------ “Unicode 类”取值如下---脚本类:   Arabic        阿拉伯文   Armenian        亚美尼亚文   Balinese        巴厘岛文   Bengali        孟加拉文   Bopomofo        汉语拼音字母   Braille        盲文   Buginese        布吉文   Buhid        布希德文   Canadian_Aboriginal  加拿大土著文   Carian        卡里亚文   Cham          占族文   Cherokee        切诺基文   Common        普通的,字符不是特定于一个脚本   Coptic        科普特文   Cuneiform      楔形文字   Cypriot        塞浦路斯文   Cyrillic        斯拉夫文   Deseret        犹他州文   Devanagari      梵文   Ethiopic        衣索比亚文   Georgian        格鲁吉亚文   Glagolitic      格拉哥里文   Gothic        哥特文   Greek        希腊   Gujarati        古吉拉特文   Gurmukhi        果鲁穆奇文   Han          汉文   Hangul        韩文   Hanunoo        哈鲁喏文   Hebrew        希伯来文   Hiragana        平假名(日语)   Inherited      继承前一个字符的脚本   Kannada        坎那达文   Katakana        片假名(日语)   Kayah_Li        克耶字母   Kharoshthi      卡罗须提文   Khmer        高棉文   Lao          老挝文   Latin        拉丁文   Lepcha        雷布查文   Limbu        林布文   Linear_B        B类线形文字(古希腊)   Lycian        利西亚文   Lydian        吕底亚文   Malayalam      马拉雅拉姆文   Mongolian      蒙古文   Myanmar        缅甸文   New_Tai_Lue      新傣仂文   Nko          Nko文   Ogham        欧甘文   Ol_Chiki        桑塔利文   Old_Italic      古意大利文   Old_Persian      古波斯文   Oriya        奥里亚文   Osmanya        奥斯曼亚文   Phags_Pa        八思巴文   Phoenician      腓尼基文   Rejang        拉让文   Runic        古代北欧文字   Saurashtra      索拉什特拉文(印度县城)   Shavian        萧伯纳文   Sinhala        僧伽罗文   Sundanese      巽他文   Syloti_Nagri      锡尔赫特文   Syriac        叙利亚文   Tagalog        塔加拉文   Tagbanwa        塔格巴努亚文   Tai_Le        德宏傣文   Tamil        泰米尔文   Telugu        泰卢固文   Thaana        塔安那文   Thai          泰文   Tibetan        藏文   Tifinagh        提非纳文   Ugaritic        乌加里特文   Vai          瓦伊文   Yi          彝文 ------------------------------------------------------------ 注意:   对于 [a-z] 这样的正则表达式,如果要在 [] 中匹配 - ,可以将 - 放在 [] 的开头或结尾,例如 [-a-z] 或 [a-z-]   可以在 [] 中使用转义字符:\f、\t、\n、\r、\v、\377、\xFF、\x{10FFFF}、\\、\^、\$、\.、\*、\+、\?、\{、\}、\(、\)、\[、\]、\|(具体含义见上面的说明)   如果在正则表达式中使用了分组,则在执行正则替换的时候,“替换内容”中可以使用 $1、${1}、$name、${name} 这样的“分组引用符”获取相应的分组内容。其中 $0 代表整个匹配项,$1 代表第 1 个分组,$2 代表第 2 个分组,……。   如果“分组引用符”是 $name 的形式,则在解析的时候,name 是取尽可能长的字符串,比如:$1x 相当于 ${1x},而不是${1}x,再比如:$10 相当于 ${10},而不是 ${1}0。   由于 $ 字符会被转义,所以要在“替换内容”中使用 $ 字符,可以用 \$ 代替。   上面介绍的正则表达式语法是“Perl 语法”,除了“Perl 语法”外,Go 语言中还有另一种“POSIX 语法”,“POSIX 语法”除了不能使用“Perl 类”之外,其它都一样。 ------------------------------------------------------------
// 示例
func main() {
    text := `Hello 世界!123 Go.`

    // 查找连续的小写字母
    reg := regexp.MustCompile(`[a-z]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["ello" "o"]

    // 查找连续的非小写字母
    reg = regexp.MustCompile(`[^a-z]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["H" " 世界!123 G" "."]

    // 查找连续的单词字母
    reg = regexp.MustCompile(`[\w]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello" "123" "Go"]

    // 查找连续的非单词字母、非空白字符
    reg = regexp.MustCompile(`[^\w\s]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["世界!" "."]

    // 查找连续的大写字母
    reg = regexp.MustCompile(`[[:upper:]]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["H" "G"]

    // 查找连续的非 ASCII 字符
    reg = regexp.MustCompile(`[[:^ascii:]]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["世界!"]

    // 查找连续的标点符号
    reg = regexp.MustCompile(`[\pP]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["!" "."]

    // 查找连续的非标点符号字符
    reg = regexp.MustCompile(`[\PP]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello 世界" "123 Go"]

    // 查找连续的汉字
    reg = regexp.MustCompile(`[\p{Han}]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["世界"]

    // 查找连续的非汉字字符
    reg = regexp.MustCompile(`[\P{Han}]+`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello " "!123 Go."]

    // 查找 Hello 或 Go
    reg = regexp.MustCompile(`Hello|Go`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello" "Go"]

    // 查找行首以 H 开头,以空格结尾的字符串
    reg = regexp.MustCompile(`^H.*\s`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello 世界!123 "]

    // 查找行首以 H 开头,以空白结尾的字符串(非贪婪模式)
    reg = regexp.MustCompile(`(?U)^H.*\s`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello "]

    // 查找以 hello 开头(忽略大小写),以 Go 结尾的字符串
    reg = regexp.MustCompile(`(?i:^hello).*Go`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello 世界!123 Go"]

    // 查找 Go.
    reg = regexp.MustCompile(`\QGo.\E`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Go."]

    // 查找从行首开始,以空格结尾的字符串(非贪婪模式)
    reg = regexp.MustCompile(`(?U)^.* `)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello "]

    // 查找以空格开头,到行尾结束,中间不包含空格字符串
    reg = regexp.MustCompile(` [^ ]*$`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // [" Go."]

    // 查找“单词边界”之间的字符串
    reg = regexp.MustCompile(`(?U)\b.+\b`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello" " 世界!" "123" " " "Go"]

    // 查找连续 1 次到 4 次的非空格字符,并以 o 结尾的字符串
    reg = regexp.MustCompile(`[^ ]{1,4}o`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello" "Go"]

    // 查找 Hello 或 Go
    reg = regexp.MustCompile(`(?:Hell|G)o`)
    fmt.Printf("%q\n", reg.FindAllString(text, -1))
    // ["Hello" "Go"]

    // 查找 Hello 或 Go,替换为 Hellooo、Gooo
    reg = regexp.MustCompile(`(?PHell|G)o`)
    fmt.Printf("%q\n", reg.ReplaceAllString(text, "${n}ooo"))
    // "Hellooo 世界!123 Gooo."

    // 交换 Hello 和 Go
    reg = regexp.MustCompile(`(Hello)(.*)(Go)`)
    fmt.Printf("%q\n", reg.ReplaceAllString(text, "$3$2$1"))
    // "Go 世界!123 Hello."

    // 特殊字符的查找
    reg = regexp.MustCompile(`[\f\t\n\r\v\123\x7F\x{10FFFF}\\\^\$\.\*\+\?\{\}\(\)\[\]\|]`)
    fmt.Printf("%q\n", reg.ReplaceAllString("\f\t\n\r\v\123\x7F\U0010FFFF\\^$.*+?{}()[]|", "-"))
    // "----------------------"
}

 

------------------------------------------------------------


原文地址: https://www.cnblogs.com/williamjie/p/9686311.html
posted @ 2020-01-06 10:22  davygeek  阅读(2139)  评论(0编辑  收藏  举报