前言

最近发现我正则表达式相关的内容好像因为太久没用,已经忘得差不多了。所以我收集了一些资料自己理了这一篇,省的以后又四处乱找。正好最近可能也要用,算是临时抱佛脚了😝

【转载说明】本文优先发布于我的个人博客www.226yzy.com ,转载请注明出处并注明作者:星空下的YZY。

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0许可协议。

(本文有参考网上资料,已列在文末)

语法

定位符

字符 描述
^ 匹配输入字符串开始的位置。
$ 匹配输入字符串结尾的位置。
\b 匹配一个单词边界,即字与空格间的位置。
\B 非单词边界匹配。

注意:不能将限定符与定位符一起使用。

限定符

字符 描述
* 匹配前面的子表达式零次或多次。例如,zo 能匹配 “z” 以及 “zoo”。 等价于{0,}。
+ 匹配前面的子表达式一次或多次。例如,’zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
? 匹配前面的子表达式零次一次。例如,”do(es)?” 可以匹配 “do” 、 “does” 中的 “does” 、 “doxy” 中的 “do” 。? 等价于 {0,1}。
{n} n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,} n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’。
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。

转义字符

字符 描述
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非单词边界。’er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\cx 匹配由 x 指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\d 匹配一个数字字符。等价于 [0-9]。
\D 匹配一个非数字字符。等价于 [^0-9]
\f 匹配一个换页符。等价于 \x0c 和 \cL。
\n 匹配一个换行符。等价于 \x0a 和 \cJ。
\r 匹配一个回车符。等价于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\t 匹配一个制表符。等价于 \x09 和 \cI。
\v 匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w 匹配字母、数字、下划线。等价于[A-Za-z0-9_]
\W 匹配非字母、数字、下划线。等价于 [^A-Za-z0-9_]
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,’\x41’ 匹配 “A”。’\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,’(.)\1’ 匹配两个连续的相同字符。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

字符集

有时我们需要匹配一类字符,字符集可以实现这个功能

例如:[a-z]是小写英文字母的字符集

在前面添加^,可表示非的意思(^在[]外表示匹配开头

例如:[^abc]够匹配abc之外的任意字符

正则还内置了一些字符集,即一些转义字符

  • .匹配除换行符(\n、\r)之外的任何单个字符 = [^\n]

  • \w =[0-9a-Z_]

  • \W = [^0-9a-Z_]
  • \s =[ \t\n\v]
  • \S = [^ \t\n\v]
  • \d =[0-9]
  • \D = [^0-9]

选择表达式

正则中用|来表示分组,a|b表示匹配a或者b的意思

修饰符(标记)

标记也称为修饰符,正则表达式的标记用于指定额外的匹配策略。

标记不写在正则表达式里,标记位于表达式之外,格式如下:

1
/pattern/flags
修饰符 含义 描述
i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g global - 全局匹配 查找所有的匹配项。
m multi line - 多行匹配 使边界字符 ^$ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

补充

以下为我自己使用了解到的其他内容补充

正则替换replace中$1的用法

例如:C++中s=regex_replace(s,regex(" (\\W)"),"$1");

$1,$2就是按顺序对应小括号里面的小正则 捕获到的内容。

上面那条是去除符号前的空格

常用正则表达式

使用前请自行测试是否正确

验证类

1
2
3
4
5
6
7
8
9
10
11
12
验证字母:/^[a-zA-Z]+$/
验证长度为3的字符:/^.{3}$/
验证由26个英文字母组成的字符串:/^[A-Za-z]+$/
验证日期YYYY-MM-DD:/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2})$/
验证邮编:/^\d{6}$/
验证日期格式YYYY-MM-DD hh:mm:ss:/^(\d{1,4})(-|\/)(\d{1,2})\2(\d{1,2}) (\d{1,2}):(\d{1,2}):(\d{1,2})$/
验证整数:/^[-+]?\d*$/
验证小数:/^[-\+]?\d+(\.\d+)?$/
验证中文:/^[\u0391-\uFFE5]+$/
验证邮箱:/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/
验证手机号:/^1[3456789]\d{9}$/
验证身份证:/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/ 【注意身份证这个只是验证字符组成是否合理,完整的还需要自己加一下运算判断】

数字类

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

字符类

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

其他

1
2
3
4
网页图片:\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)
强密码:字母+数字+特殊字符^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&*]+$)(?![\d!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$
中密码:字母+数字,字母+特殊字符,数字+特殊字符^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$
弱密码:纯数字,纯字母,纯特殊字符^(?:\d+|[a-zA-Z]+|[!@#$%^&*]+)$

以上内容请自行再辩证判断

示例

字符串替换

题目详情 - L1-064 估值一亿的AI核心代码 (20 分) (pintia.cn)

就挑这个吧

规则是:

  • 无论用户说什么,首先把对方说的话在一行中原样打印出来;
  • 消除原文中多余空格:把相邻单词间的多个空格换成 1 个空格,把行首尾的空格全部删掉,把标点符号前面的空格删掉;
  • 把原文中所有大写英文字母变成小写,除了 I
  • 把原文中所有独立的 can youcould you 对应地换成 I canI could—— 这里“独立”是指被空格或标点符号分隔开的单词;
  • 把原文中所有独立的 Ime 换成 you
  • 把原文中所有的问号 ? 换成惊叹号 !
  • 在一行中输出替换后的句子作为 AI 的回答。

这用正则就省事很多了🤣

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
getchar();
while(n--){
string s;
getline(cin,s);
cout<<s<<endl;
for(int i=0;i<s.length();i++)
if(s[i]!='I')s[i]=tolower(s[i]);
s=regex_replace(s,regex(" +")," ");
if(s[0]==' ')s.erase(0,1);
if(s[s.length()-1]==' ')s.erase(s.length()-1,1);
s=regex_replace(s,regex(" (\\W)"),"$1");
s=regex_replace(s,regex("\\bcan you\\b"),"A");
s=regex_replace(s,regex("\\bcould you\\b"),"B");
s=regex_replace(s,regex("\\b(I|me)\\b"),"C");
s=regex_replace(s,regex("A"),"I can");
s=regex_replace(s,regex("B"),"I could");
s=regex_replace(s,regex("C"),"you");
s=regex_replace(s,regex("\\?"),"!");
cout<<"AI: "<<s<<endl;
}
}

java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
String s;
int n=Integer.parseInt(sc.nextLine());
for(int i=0;i<n;i++) {
s=sc.nextLine();
System.out.println(s);
String ans="";
char[] ss=s.toCharArray();
for(int j=0;j<ss.length;j++){
if(ss[j]>='A'&&ss[j]<='Z'&&ss[j]!='I') {
ss[j]+=32;
//ss[j]=Character.toLowerCase(ss[j]);
}
ans+=ss[j];
}
ans=ans.trim();
ans=ans.replaceAll(" +", " ");
ans=ans.replaceAll(" (\\W)", "$1");
ans=ans.replaceAll("\\?", "!");
ans=ans.replaceAll("\\bcan you\\b","A");
ans=ans.replaceAll("\\bcould you\\b","B");
ans=ans.replaceAll("\\b(I|me)\\b","C");
ans=ans.replaceAll("A","I can");
ans=ans.replaceAll("B","I could");
ans=ans.replaceAll("C","you");
System.out.println("AI: "+ans);
}
}
}

判断是否符合正则表达式

留一个(怕自己忘了😂)

java

1
2
3
4
5
6
7
8
9
10
import java.util.regex.*;
class RegexExample1{
public static void main(String[] args){
String content = "I am noob " +
"from runoob.com.";
String pattern = ".*runoob.*";
boolean isMatch = Pattern.matches(pattern, content);
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch);
}
}

参考文献

正则表达式 – 语法 | 菜鸟教程 (runoob.com)

正则表达式教程——语法篇 - 知乎 (zhihu.com)

正则替换replace中$1的用法 - FEDeveloper - 博客园 (cnblogs.com)

正则表达式入门|常见的js正则表达式 - 知乎 (zhihu.com)

最全常用正则表达式大全ZhaoYingChao88的博客-CSDN博客常用正则表达式

JavaScript 之 密码强度的正则校验zhuangwei_8256的博客-CSDN博客密码强度校验正则

cdoco/common-regex: 常用正则表达式 - 收集一些在平时项目开发中经常用到的正则表达式。 (github.com)

cdoco/learn-regex-zh: 翻译: 学习正则表达式的简单方法 (github.com)

最后

暂时就写到这了

欢迎访问我的小破站https://www.226yzy.com/ 或者GitHub版镜像 https://226yzy.github.io/ 或Gitee版镜像https://yzy226.gitee.io/

我的Github:226YZY (星空下的YZY) (github.com)

【转载说明】本文优先发布于我的个人博客www.226yzy.com ,转载请注明出处并注明作者:星空下的YZY。

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0许可协议。