正则表达式
正则表达式(regularexpression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。
1. 普通字符:
字符 | 描述 |
---|---|
[ABC] | 匹配[…]中的字符 |
[^ABC] | 匹配除[…]中的字符 |
[A-Z] | 匹配[…]区间中的字符 |
\s | 匹配任意空白字符(包括空格、制表符、换行等) |
\S | 匹配任意非空字符 |
\d | 匹配任意数字 |
\D | 匹配任意非数字 |
\w | 匹配包括下划线的任意单词字符 => [A-Za-z0-9 |
\W | 匹配任意非单词字符 => [^A-Za-z90-9] |
\Xn | 匹配n,其中n为十六进制转义值 例如"\x41"匹配A |
\Un | 匹配n,其中n是一个用四个十六进制数字表示的Unicode字符 |
2. 非打印字符
字符 | 描述 |
---|---|
\cx | 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z 或 a-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符 |
\f | 匹配一个换页符 |
\n | 匹配一个换行符 |
\r | 匹配一个回车符 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
3. 特殊字符
字符 | 描述 |
---|---|
$ | 匹配输入字符串结尾位置 |
() | 标记子表达式 |
* | 匹配前面子表达式零次或多次 |
+ | 匹配前面的子表达式一次或多次 |
. | 匹配除换行符\n之外的任何字符 |
[] | 匹配中括号表达式限定字符 |
? | 匹配前面子表达式零次或一次,或指明一个非贪婪限定符 |
\ | 转义字符 |
^ | 匹配输入字符串的开始位置,方括号表达式中表示不接受该方括号表达式中的字符集合 |
{} | 标记限定符表达式 |
\ | 指明两项之间的一个选择 |
.* | 匹配任意长度的任意字符 |
4. 限定符
字符 | 描述 |
---|---|
* | 匹配前面子表达式零次或多次 |
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面子表达式零次或一次,或指明一个非贪婪限定符 |
{n} | n 是一个非负整数,确定匹配 n 次 |
{n, | n 是一个非负整数,至少匹配 n 次 |
{n,m} | m 和 n 均为非负证书,最少匹配 n 次且最多匹配 m次 |
5. 定位符
字符 | 描述 |
---|---|
^ | 匹配输入字符开始位置 |
$ | 匹配输入字符结尾位置 |
\b | 匹配一个单词边界,即字与空格间的位置 |
\B | 匹配一个非单词边界 |
6. 贪婪匹配和非贪婪匹配
名称 | 概念 |
---|---|
贪婪匹配 | 在整个表达式匹配成功前提下,尽可能多的匹配 |
非贪婪匹配 | 在整个表达式匹配成功的前提下,尽可能少的匹配 |
* 和 + 和 ? | 都是贪婪的,尽可能匹配多的字符,只要在它们后面加上一个 ? 就可以实现非贪婪匹配 |
? | 非贪婪限定符 |
7. ? 的组合用法
字符 | 描述 |
---|---|
?= | exp1(?=exp2):正向肯定检查,查找exp1后面exp2的exp1 |
?<= | (?<=exp2)exp1:反向肯定检查,查找exp1前面是exp2的exp1 |
?! | exp1(?!exp2):正向否定查找exp1后面不是exp2的exp1 |
?<! | (?<!exp2)exp1:反向否定查找exp1前面不是exp2的exp1 |
(?:pattern) | 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用 |
(pattern) | 获取匹配,匹配pattern并获取匹配结果 |
Python re库
基本用法 | 描述 |
---|---|
re.I | 忽略大小写 |
re.M | 多行模式,改变’^‘和’$‘的行为 |
re.S | 点任意匹配模式,改变’.'的行为 |
re.L | 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定 |
re.U | 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性 |
re.X | 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释 |
函数 | 描述 |
---|---|
re.findall() | 搜索所有满足条件的字符串 |
re.match() | 从第一个字符开始匹配模式 |
re.search() | 搜索第一个满足条件的字符串,查找到第一个停止 |
re.sub() | 替换满足条件的字符串 |
re.compile() | 创建模式对象,可以实现更有效率的匹配 |
re.escape(string) | 把string中,除了字母和数字以外的字符,都加上反斜杠 |
- pattern是用compile创建的模式对象。如下:
import re
some_text = 'a,b,,,,c d'
reObj = re.compile('[, ]+')
reObj.split(some_text)
['a', 'b', 'c', 'd']
- 不使用re.compile在进行search,match等操作前不适用compile函数,会导致重复使用模式时,需要对模式进行重复的转换。降低匹配速度。而此种方法的调用方式,更为直观。如下:
import re
some_text = 'a,b,,,,c d'
re.split('[, ]+',some_text)
['a', 'b', 'c', 'd']
练习
1. 将masscan扫描结果格式化存入表格中:
- 测试数据如下:
# masscan
Discovered open port 6667/tcp on 10.10.10.254
Discovered open port 139/tcp on 10.10.10.142
Discovered open port 512/tcp on 10.10.10.254
Discovered open port 5040/tcp on 10.10.10.142
Discovered open port 6000/tcp on 10.10.10.254
Discovered open port 51849/tcp on 10.10.10.254
Discovered open port 5357/tcp on 10.10.10.142
Discovered open port 3306/tcp on 10.10.10.142
Discovered open port 1099/tcp on 10.10.10.254
Discovered open port 6697/tcp on 10.10.10.254
Discovered open port 3306/tcp on 10.10.10.254
Discovered open port 49666/tcp on 10.10.10.142
Discovered open port 44453/tcp on 10.10.10.254
Discovered open port 49674/tcp on 10.10.10.142
Discovered open port 514/tcp on 10.10.10.254
Discovered open port 49664/tcp on 10.10.10.142
Discovered open port 80/tcp on 10.10.10.142
Discovered open port 8787/tcp on 10.10.10.254
Discovered open port 5900/tcp on 10.10.10.254
Discovered open port 23/tcp on 10.10.10.254
Discovered open port 37692/tcp on 10.10.10.254
Discovered open port 5432/tcp on 10.10.10.254
Discovered open port 49665/tcp on 10.10.10.142
Discovered open port 8009/tcp on 10.10.10.254
Discovered open port 8180/tcp on 10.10.10.254
Discovered open port 25/tcp on 10.10.10.254
Discovered open port 1433/tcp on 10.10.10.142
Discovered open port 513/tcp on 10.10.10.254
Discovered open port 135/tcp on 10.10.10.142
Discovered open port 445/tcp on 10.10.10.142
Discovered open port 2049/tcp on 10.10.10.254
Discovered open port 22/tcp on 10.10.10.254
Discovered open port 80/tcp on 10.10.10.254
Discovered open port 3632/tcp on 10.10.10.254
Discovered open port 53/tcp on 10.10.10.2
Discovered open port 49669/tcp on 10.10.10.142
Discovered open port 50165/tcp on 10.10.10.254
Discovered open port 49667/tcp on 10.10.10.142
Discovered open port 49680/tcp on 10.10.10.142
Discovered open port 1524/tcp on 10.10.10.254
Discovered open port 53/tcp on 10.10.10.254
Discovered open port 21/tcp on 10.10.10.254
Discovered open port 111/tcp on 10.10.10.254
Discovered open port 2121/tcp on 10.10.10.254
Discovered open port 445/tcp on 10.10.10.254
Discovered open port 80/tcp on 10.10.10.143
Discovered open port 3306/tcp on 10.10.10.143
Discovered open port 49666/tcp on 192.168.1.109
Discovered open port 139/tcp on 192.168.1.109
Discovered open port 443/tcp on 192.168.1.109
Discovered open port 445/tcp on 192.168.1.109
Discovered open port 5040/tcp on 192.168.1.109
Discovered open port 912/tcp on 192.168.1.109
Discovered open port 49668/tcp on 192.168.1.109
Discovered open port 49670/tcp on 192.168.1.109
Discovered open port 3389/tcp on 192.168.1.109
Discovered open port 49665/tcp on 192.168.1.109
Discovered open port 5357/tcp on 192.168.1.109
Discovered open port 49664/tcp on 192.168.1.109
Discovered open port 49671/tcp on 192.168.1.109
- 执行代码如下:
import re
import csv
import pandas as pd
if __name__ == '__main__':
with open("masscan_data.csv","w", newline='') as datafile:
writer = csv.writer(datafile)
writer.writerow(["Address", 'Protocol', 'Port'])
results = []
with open("test.txt", "r") as file:
lines = file.readlines()
for line in lines:
ip = re.findall(r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}", line) # 匹配ip
port_protocol = re.search(r"[0-9]{1,5}/\S*", line) # 匹配协议即端口
try:
portID = port_protocol.group()
portinfo = portID.split('/')
protocol = portinfo[1]
port = portinfo[0]
result = [ip[0], protocol, port]
# results.append(result)
writer.writerow(result)
except:
pass
# for result in results:
# print(result)
df = pd.read_csv('masscan_data.csv')
df = df.sort_values(by=['Address', 'Port'], ascending=True)
df.to_csv('masscan_data.csv',index=False)
df_sum = df.groupby('Address')['Port'].count() # 统计扫描出的各个ip地址有多少端口
df_sum.to_csv('masscan_sum.csv')
2. 匹配密码,手机号,邮箱:
import re
def input_pwd():
while 1:
pwd = input('Please Input Your Password: ')
if len(pwd) < 8:
print('Too short')
elif not lower.findall(pwd):
print('You have no lower letters!!!')
continue
elif not upper.findall(pwd):
print('You have no upper letters!!!')
continue
elif not digit.findall(pwd):
print('You have no digits!!!')
continue
elif not special.findall(pwd):
print('You have no special characters!!!')
else:
print('Correct!')
break
return pwd
def input_phone():
while 1:
phone = input('Please Input Your phone number: ')
if len(phone) != 11:
print('Format error!')
elif re.findall(r"1(3|4|5|7|8)\d{9}$", phone):
phone_number = re.findall(r"1(?:3|4|5|7|8)[0-9]{9}$", phone)
print('Correct')
break
else:
print('Format error!')
return phone_number[0]
def input_email():
while 1:
email = input('Please Input Your email number: ')
if re.findall(r"[a-z0-9]+@(?:163|gmail|qq)\.com", email, re.I):
email_number = re.findall(r"[a-z0-9]+@(?:163|gmail|qq)\.com", email, re.I)
print('Correct')
break
else:
print('Format error!')
return email_number[0]
if __name__ == '__main__':
lower = re.compile('[a-z]')
upper = re.compile('[A-Z]')
digit = re.compile('[0-9]')
special = re.compile('[^a-zA-Z0-9]')
password = input_pwd()
pho = input_phone()
ema = input_email()
print("\nYour pwd: " + password + "\nYour phone: " + pho + "\nYour email: " + ema)
参考链接:
https://tool.oschina.net/uploads/apidocs/jquery/regexp.html(表达式全集)
https://www.runoob.com/regexp/regexp-syntax.html(正则表达式语法)
https://blog.csdn.net/stcaaa/article/details/83864210(python re库 详解)
https://blog.csdn.net/qq_40279964/article/details/82958680(贪婪匹配与非贪婪匹配)