正则表达式及其在Java和Python中的应用
学了很多遍正则表达式,总是一学就忘quq,这次,我一定要,记住
正则表达式相关知识
所谓正则表达式,就是用一种格式去表达你想要的字符串的模式,然后用来比较、匹配和查找。
基本语法
原子
原子就是字符串中不可分割的部分,一个字符是一个原子,一个转义字符(例如"")也是一个原子。
递归的定义:()
括起来的多个原子(或者说一个正则表达式)构成一个原子。
例如(ab)代表原子ab,在匹配时,原子内部的内容代表一个整体,不可拆分
中括号和花括号
[]
括起来的原子代表匹配时匹配上其中的任何一个就行
[^]
为非原子表,它所能匹配的东西刚好取不加^
时的补集- 另一种语法是
[a-z]
代表az之间(在ASCII表中)的所有字符
{}
可以放原子或者中括号表达式后面,里面写上数字,表示前面的原子出现的次数
数字的形式可以是 {m} {m,n} {m,}
(闭区间)
特殊字符
转义字符
转义字符就是用一个字符代表某一类字符
字符 | 含义 |
---|---|
\d | 匹配一个数字 |
\w | 匹配字母数字或下划线 |
\s | 匹配一个空白字符,相当于[\f\n\r\t\v] |
这几种字符如果后面字母换成大写就代表取反(\S
等价于
[^\s]
)
元字符
元字符是有特殊含义的字符,如果要在正则表达式中包含元字符本身,必须在其前加上””进行转义
字符 | 含义 |
---|---|
* | 前面的原子匹配任何次 |
+ | 前面的原子匹配一次或以上 |
? | 前面的原子匹配0或1次 |
^ | 匹配字符串首的位置 |
$ | 匹配字符串尾的位置 |
\b | 匹配字符串的边界(\B反) |
. | 除换行符外的任何字符 |
可以看到,这些元字符或者对其前面字符的匹配模式有所影响,或者匹配某个位置
模式修正符
还有一个东西叫模式修正符,表示匹配的模式(如忽略大小写这些)。
最常用的就是忽略大小写了,其他的我也不懂,等用到的时候补充。
修饰符 | 描述 |
---|---|
I | 忽略大小写 |
L | 做本地化识别匹配 |
M | 多行匹配 |
S | 使.匹配包括换行在内的所有字符 |
U | 根据Unicode字符集解析字符 |
X | 详细模式,正则表达式可以有多行 |
有的时候你看到的正则表达式是写在两个斜杠之间的,比如/abc/
这个斜杠其实没有什么意思,只是表达这是一条正则表达式,在编程的时候不用管这两个斜杠,只用把两个杠之间的东西当做pattern就行。
一般在写正则表达式的时候,会把模式修正符放在右斜杠的右边,比如/abc/i
表示匹配这个字符串并且忽略大小写。
捕获组
这里就要介绍()
的另一个含义:
被括号括起来的东西叫模式单元,在匹配结束后,系统自动将模式单元中的匹配储存起来,可以进行引用。
当需要指定一个模式单元不被储存的时候,可以用(?: )
命名捕获组:(?<name>expression)
(在Python中是(?P<name>expression)
)
捕获组的编号
零号一般代表整个匹配结果,从左到右根据(
出现的先后编号
不过要是括号比较多的话,建议使用命名捕获组
非贪婪匹配
如果用表达式(.*)
去匹配一个字符串,应该能匹配一整行,因为正则表达式默认贪婪匹配,也就是说,在满足条件的情况下尽可能多的匹配字符。
但是如果我们不想要匹配这么多字符呢?
一种解决方法是用{数字}
替代元字符,这样就能指定匹配的次数,但是要是预先不知道次数呢?
可以使用非贪婪匹配
代表匹配次数的元字符后面加上?
表示非贪婪匹配,含义是在满足条件的情况下尽可能少的匹配。
例如:"(\d*?)(0*)"
匹配字符串后面的0
了解了这些正则表达式中的基本知识,下面来看看这些功能在具体的编程语言中应该怎么实现。
Python的Re库
主要用到的函数
re.compile(pattern)
可输入输入字符,转化为匹配对象
在需要多次使用一个pattern的时候最好先compile而不是直接拿字符串去匹配,这样能加快速度。
第二个参数的位置可以输入模式修正符,例如:
1
2pattern = re.compile(r"abc",re.I)
#还有一件事:上面的字符串前面有一个r,代表这个字符串不进行转义re.***(pattern,string)
这里的pattern可以是字符串,也可以是用compile创建的模式对象
下面这几个函数的调用都是上面的格式:
re.findall():搜索所有满足条件的字符串,返回一个列表
re.match():从第一个字符开始匹配,返回匹配对象
可以用group()查看匹配到的结果,用start(),end()获取匹配的开始以及结束位置
re.fullmatch(): 用pattern去匹配整个字符串
re.search():搜索第一个满足条件的字符串,查找到第一个停止
re.sub(pattern,rep,string,mood)
pattern 为需要寻找的模式
rep 是要替换为的东西
string 原字符串
mood选项(用来控制替换的数量等)
小例子:
就是说咱有多懒,写个脚本把字符串中的"{name}"这些东西换成 "%s"(OO作业
1
2
3
4
5
6
7>import re
>s = input()
>while (s != "q"):
s = input()
pattern = "{.*?}" # 非贪婪
ss = re.sub(pattern, "%s", s)
print( ss + "\\n")
Java与字符串
不用正则表达式的简单处理
split()
用额定字符串分割字符串, 不会输出空字符串indexOf()
搜索字符串出现的位置subString()
截取子串trim()
删除前后空格以及换行符- 判断字符串相等不能用
==
(而Python中是可以的),用==
只是判断地址。应该用s1.equals(s2)
判断
正则表达式
类
Pattern类
Pattern 类对象是由
Pattern.compile()
函数返回的Matcher类
由Pattern对象的matcher()方法返回
方法:
group()输入捕获组的编号或者名称,返回对应的字符串
start([int group]) 可以输入group的编号,如果不输入参数,默认
方法
匹配方法
在调用group(),start()等方法获取信息之前,要先进行匹配,否则会报错
find() 从上一次匹配到的字符串结束的地方开始匹配
例如:
1
2
3
4
5
6
7
8
9
10
11
12String REGEX = "csc";
String INPUT =
"cscscore";
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
for (int i=0;i<2;i++) {
// 第二次匹配是从位置3开始的,所以第二次是匹配不到的
if(m.find())
System.out.println(m.start());
else
System.out.println("Not found");
}find还可以输入一个int参数,表示匹配开始的位置
lookingAt() 从头开始匹配
matches()
相当于Python里面的fullmatch() ,尝试将整个区域与模式匹配
替换方法
replaceFirst()
replaceAll()
appendReplacement() 和appendTail()
看一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class RegexMatches
{
private static String REGEX = "a*b";
private static String INPUT = "aabfooaabfooabfoobkkk";
private static String REPLACE = "-";
public static void main(String[] args) {
Pattern p = Pattern.compile(REGEX);
Matcher m = p.matcher(INPUT);
StringBuffer sb = new StringBuffer();//新建一个空的StringBuffer
while(m.find()){
m.appendReplacement(sb,REPLACE);
}
m.appendTail(sb);
System.out.println(sb.toString());
//输出为-foo-foo-foo-kkk
}
}appendReplacement就是把从上一次匹配结束(或者0位置)到这一次匹配结束并且替换后的这一段字符串加到StringBuffer结尾
appendTail就是把上一次匹配结束的位置到结尾的部分都加到StringBuffer结尾