|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
引言
在当今数据爆炸的时代,文本处理已成为日常工作中不可或缺的一部分。无论是数据分析、日志处理、信息提取还是数据验证,我们经常需要从大量文本中快速准确地找到所需信息。正则表达式(Regular Expression,简称regex或regexp)就是这样一种强大而灵活的文本处理工具,它能够帮助我们以简洁的方式描述和匹配复杂的文本模式,从而极大地提高工作效率。
正则表达式最初由数学家斯蒂芬·科尔·克莱尼(Stephen Cole Kleene)在1950年代提出,后来被广泛应用于计算机科学领域。如今,几乎所有主流编程语言都支持正则表达式,使其成为程序员和数据分析师必备的技能之一。
本文将从正则表达式的基础概念讲起,逐步深入到高级技巧,通过丰富的实例和详细的代码演示,帮助读者全面掌握正则表达式,轻松应对各种文本处理挑战,提高工作效率,成为数据处理高手。
正则表达式基础
什么是正则表达式
正则表达式是一种用于描述字符串模式的强大工具,它由一系列特殊字符和普通字符组成,可以用来检查一个字符串是否含有某种子串、将匹配的子串替换或者从某个字符串中取出符合某个条件的子串等。
简单来说,正则表达式就像是一种”迷你语言”,专门用来处理文本。通过这种语言,我们可以告诉计算机我们想要查找什么样的文本,而不需要明确指定具体的文本内容。
基本语法和元字符
正则表达式的基本语法由普通字符和元字符组成。普通字符(如字母、数字、汉字等)会匹配自身,而元字符则具有特殊的含义。
以下是一些常用的元字符及其含义:
• .:匹配除换行符以外的任意单个字符
• *:匹配前面的子表达式零次或多次
• +:匹配前面的子表达式一次或多次
• ?:匹配前面的子表达式零次或一次
• ^:匹配字符串的开始位置
• $:匹配字符串的结束位置
• \:转义字符,用于匹配特殊字符本身
• |:选择符,匹配”|“左右任意一个表达式
• ():分组,将括号内的表达式作为一个整体
• []:字符类,匹配方括号中的任意一个字符
让我们通过一些简单的例子来理解这些元字符的使用:
- import re
- # 匹配以"hello"开头的字符串
- pattern = r"^hello"
- text = "hello world"
- print(re.match(pattern, text)) # 输出: <re.Match object; span=(0, 5), match='hello'>
- # 匹配以"world"结尾的字符串
- pattern = r"world$"
- text = "hello world"
- print(re.search(pattern, text)) # 输出: <re.Match object; span=(6, 11), match='world'>
- # 匹配包含"l"的字符串
- pattern = r"l"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['l', 'l', 'l']
- # 匹配"hello"或"world"
- pattern = r"hello|world"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['hello', 'world']
复制代码
字符类和预定义字符集
字符类允许我们匹配一组字符中的任意一个。字符类使用方括号[]表示,例如[abc]可以匹配”a”、”b”或”c”中的任意一个字符。
在字符类中,还可以使用连字符-表示范围,例如[a-z]表示任意小写字母,[0-9]表示任意数字。
此外,正则表达式还提供了一些预定义的字符集,方便我们使用:
• \d:匹配任意数字,相当于[0-9]
• \D:匹配任意非数字字符,相当于[^0-9]
• \w:匹配任意单词字符,包括字母、数字和下划线,相当于[a-zA-Z0-9_]
• \W:匹配任意非单词字符,相当于[^a-zA-Z0-9_]
• \s:匹配任意空白字符,包括空格、制表符、换行符等
• \S:匹配任意非空白字符
让我们看一些例子:
- import re
- # 匹配任意数字
- pattern = r"\d"
- text = "hello 123 world"
- print(re.findall(pattern, text)) # 输出: ['1', '2', '3']
- # 匹配任意单词字符
- pattern = r"\w"
- text = "hello_world 123"
- print(re.findall(pattern, text)) # 输出: ['h', 'e', 'l', 'l', 'o', '_', 'w', 'o', 'r', 'l', 'd', '1', '2', '3']
- # 匹配任意空白字符
- pattern = r"\s"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: [' ']
- # 匹配元音字母
- pattern = r"[aeiou]"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['e', 'o', 'o']
- # 匹配非元音字母
- pattern = r"[^aeiou]"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['h', 'l', 'l', ' ', 'w', 'r', 'l', 'd']
复制代码
量词
量词用于指定前面的字符或表达式出现的次数。常用的量词有:
• *:匹配前面的子表达式零次或多次
• +:匹配前面的子表达式一次或多次
• ?:匹配前面的子表达式零次或一次
• {n}:匹配前面的子表达式恰好n次
• {n,}:匹配前面的子表达式至少n次
• {n,m}:匹配前面的子表达式至少n次,至多m次
让我们通过一些例子来理解量词的使用:
- import re
- # 匹配0个或多个数字
- pattern = r"\d*"
- text = "abc123def"
- print(re.findall(pattern, text)) # 输出: ['', '', '', '123', '', '', '']
- # 匹配1个或多个数字
- pattern = r"\d+"
- text = "abc123def"
- print(re.findall(pattern, text)) # 输出: ['123']
- # 匹配0个或1个数字
- pattern = r"\d?"
- text = "abc123def"
- print(re.findall(pattern, text)) # 输出: ['', '', '', '1', '2', '3', '', '', '']
- # 匹配恰好3个数字
- pattern = r"\d{3}"
- text = "abc123def4567"
- print(re.findall(pattern, text)) # 输出: ['123', '456']
- # 匹配至少2个数字
- pattern = r"\d{2,}"
- text = "abc123def4567"
- print(re.findall(pattern, text)) # 输出: ['123', '4567']
- # 匹配2到4个数字
- pattern = r"\d{2,4}"
- text = "abc123def4567"
- print(re.findall(pattern, text)) # 输出: ['123', '4567']
复制代码
边界匹配
边界匹配用于指定匹配的位置,而不是匹配具体的字符。常用的边界匹配符有:
• ^:匹配字符串的开始位置
• $:匹配字符串的结束位置
• \b:匹配单词边界
• \B:匹配非单词边界
让我们看一些例子:
- import re
- # 匹配以"hello"开头的字符串
- pattern = r"^hello"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['hello']
- # 匹配以"world"结尾的字符串
- pattern = r"world$"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['world']
- # 匹配单词"world"
- pattern = r"\bworld\b"
- text = "hello world"
- print(re.findall(pattern, text)) # 输出: ['world']
- # 匹配包含"world"但不作为单词的字符串
- pattern = r"\Bworld\B"
- text = "helloworldhello"
- print(re.findall(pattern, text)) # 输出: ['world']
复制代码
正则表达式进阶
分组和捕获
分组是正则表达式中非常重要的概念,它允许我们将多个字符或表达式作为一个整体来处理。分组使用圆括号()表示。
分组不仅可以用于应用量词,还可以用于捕获匹配的内容。当我们使用分组时,正则表达式引擎会”记住”分组匹配的内容,以便后续使用。
让我们看一些例子:
- import re
- # 匹配连续出现的相同单词
- pattern = r"(\w+)\s+\1"
- text = "hello hello world"
- print(re.findall(pattern, text)) # 输出: ['hello']
- # 提取日期中的年、月、日
- pattern = r"(\d{4})-(\d{2})-(\d{2})"
- text = "Today is 2023-07-15."
- match = re.search(pattern, text)
- if match:
- print("Year:", match.group(1)) # 输出: Year: 2023
- print("Month:", match.group(2)) # 输出: Month: 07
- print("Day:", match.group(3)) # 输出: Day: 15
- print("Full match:", match.group(0)) # 输出: Full match: 2023-07-15
- # 使用命名分组
- pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
- text = "Today is 2023-07-15."
- match = re.search(pattern, text)
- if match:
- print("Year:", match.group("year")) # 输出: Year: 2023
- print("Month:", match.group("month")) # 输出: Month: 07
- print("Day:", match.group("day")) # 输出: Day: 15
复制代码
反向引用
反向引用是指引用前面捕获组匹配的内容。在正则表达式中,我们可以使用\1、\2等来引用第一个、第二个捕获组匹配的内容。
反向引用常用于查找重复的单词或模式。让我们看一些例子:
- import re
- # 查找重复的单词
- pattern = r"\b(\w+)\s+\1\b"
- text = "hello hello world world"
- print(re.findall(pattern, text)) # 输出: ['hello', 'world']
- # 查找重复的数字
- pattern = r"(\d+)\s+\1"
- text = "123 123 456 456"
- print(re.findall(pattern, text)) # 输出: ['123', '456']
- # 查找HTML标签对
- pattern = r"<(\w+)>.+?</\1>"
- text = "<div>Hello</div> <span>World</span>"
- print(re.findall(pattern, text)) # 输出: ['div', 'span']
复制代码
非捕获组
有时候,我们使用分组只是为了应用量词或者构建复杂的模式,而不需要捕获匹配的内容。这时,我们可以使用非捕获组(?:...)来避免不必要的捕获,提高正则表达式的效率。
让我们看一些例子:
- import re
- # 使用捕获组
- pattern = r"(hello|world)+"
- text = "hellohelloworld"
- match = re.search(pattern, text)
- if match:
- print("Groups:", match.groups()) # 输出: Groups: ('world',)
- # 使用非捕获组
- pattern = r"(?:hello|world)+"
- text = "hellohelloworld"
- match = re.search(pattern, text)
- if match:
- print("Groups:", match.groups()) # 输出: Groups: ()
- # 提取IP地址
- pattern = r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
- text = "Server IP is 192.168.1.1."
- print(re.findall(pattern, text)) # 输出: ['192.168.1.1']
复制代码
零宽断言
零宽断言是一种特殊的匹配,它匹配的是位置而不是字符。零宽断言不会消耗字符,也就是说,它只是检查某个位置是否满足条件,但不会将该位置的字符包含在匹配结果中。
常用的零宽断言有:
• (?=...):正向先行断言,表示后面的位置必须匹配...
• (?!...):负向先行断言,表示后面的位置不能匹配...
• (?<=...):正向后行断言,表示前面的位置必须匹配...
• (?<!...):负向后行断言,表示前面的位置不能匹配...
让我们看一些例子:
- import re
- # 正向先行断言:匹配后面跟着"world"的"hello"
- pattern = r"hello(?=\sworld)"
- text = "hello world, hello there"
- print(re.findall(pattern, text)) # 输出: ['hello']
- # 负向先行断言:匹配后面不跟着"world"的"hello"
- pattern = r"hello(?!\sworld)"
- text = "hello world, hello there"
- print(re.findall(pattern, text)) # 输出: ['hello']
- # 正向后行断言:匹配前面是"hello"的"world"
- pattern = r"(?<=hello\s)world"
- text = "hello world, hi world"
- print(re.findall(pattern, text)) # 输出: ['world']
- # 负向后行断言:匹配前面不是"hello"的"world"
- pattern = r"(?<!hello\s)world"
- text = "hello world, hi world"
- print(re.findall(pattern, text)) # 输出: ['world']
- # 提取金额数字
- pattern = r"(?<=\$)\d+"
- text = "Price: $100, $200, $300"
- print(re.findall(pattern, text)) # 输出: ['100', '200', '300']
复制代码
贪婪与非贪婪匹配
默认情况下,正则表达式的量词是”贪婪”的,这意味着它们会尽可能多地匹配字符。例如,表达式a.*b会匹配从第一个”a”到最后一个”b”之间的所有字符,而不是到第一个”b”就停止。
有时候,我们可能需要”非贪婪”匹配,即尽可能少地匹配字符。在量词后面加上?可以使其变为非贪婪模式。
让我们看一些例子:
- import re
- # 贪婪匹配
- pattern = r"a.*b"
- text = "aabab"
- print(re.findall(pattern, text)) # 输出: ['aabab']
- # 非贪婪匹配
- pattern = r"a.*?b"
- text = "aabab"
- print(re.findall(pattern, text)) # 输出: ['aab', 'ab']
- # 贪婪匹配HTML标签内容
- pattern = r"<div>.*</div>"
- text = "<div>Hello</div><div>World</div>"
- print(re.findall(pattern, text)) # 输出: ['<div>Hello</div><div>World</div>']
- # 非贪婪匹配HTML标签内容
- pattern = r"<div>.*?</div>"
- text = "<div>Hello</div><div>World</div>"
- print(re.findall(pattern, text)) # 输出: ['<div>Hello</div>', '<div>World</div>']
- # 贪婪匹配引号内的内容
- pattern = r"'.*'"
- text = "'Hello', 'World'"
- print(re.findall(pattern, text)) # 输出: ["'Hello', 'World'"]
- # 非贪婪匹配引号内的内容
- pattern = r"'.*?'"
- text = "'Hello', 'World'"
- print(re.findall(pattern, text)) # 输出: ["'Hello'", "'World'"]
复制代码
正则表达式高级技巧
回溯控制
回溯是正则表达式引擎在匹配过程中的一种机制,当一条路径匹配失败时,引擎会回退到上一个决策点,尝试其他可能的匹配路径。虽然回溯使得正则表达式更加灵活,但过多的回溯会导致性能下降,甚至造成”灾难性回溯”(Catastrophic Backtracking)。
为了避免过多的回溯,我们可以使用原子组(?>...)和占有量词?+、*+、++、{n,m}+来限制回溯。
让我们看一些例子:
- import re
- # 普通分组(可能导致灾难性回溯)
- pattern = r"(\d+)+"
- text = "1234567890"
- print(re.findall(pattern, text)) # 输出: ['1234567890']
- # 原子组(限制回溯)
- pattern = r"(?>\d+)+"
- text = "1234567890"
- print(re.findall(pattern, text)) # 输出: ['1234567890']
- # 占有量词(限制回溯)
- pattern = r"\d++"
- text = "1234567890"
- print(re.findall(pattern, text)) # 输出: ['1234567890']
- # 避免灾难性回溯的例子
- # 这个正则表达式在匹配不成功的嵌套括号时会导致灾难性回溯
- pattern = r"\(((?>[^()]+|(?R))*)\)"
- text = "(" + "a" * 30 # 嵌套很深的字符串
- try:
- re.search(pattern, text)
- except re.error:
- print("Regex error occurred") # 可能会输出这个错误
- # 优化后的正则表达式,避免灾难性回溯
- pattern = r"\(([^()]*)\)"
- text = "(" + "a" * 30
- try:
- re.search(pattern, text)
- print("No error occurred") # 会输出这个
- except re.error:
- print("Regex error occurred")
复制代码
条件匹配
条件匹配允许我们根据某个条件是否满足来决定匹配的模式。条件匹配的语法为(?(condition)yes-pattern|no-pattern),其中condition可以是一个捕获组的编号或名称,也可以是一个断言。
让我们看一些例子:
- import re
- # 如果有捕获组1,则匹配"yes",否则匹配"no"
- pattern = r"(\d)?(?(1)yes|no)"
- text1 = "123yes"
- text2 = "abcno"
- print(re.findall(pattern, text1)) # 输出: ['1', 'yes']
- print(re.findall(pattern, text2)) # 输出: ['', 'no']
- # 如果前面有"hello",则匹配"world",否则匹配"there"
- pattern = r"(hello)?(?(1)world|there)"
- text1 = "helloworld"
- text2 = "hi there"
- print(re.findall(pattern, text1)) # 输出: ['hello', 'world']
- print(re.findall(pattern, text2)) # 输出: ['', 'there']
- # 使用命名条件
- pattern = r"(?P<word>hello)?(?(word)world|there)"
- text1 = "helloworld"
- text2 = "hi there"
- print(re.findall(pattern, text1)) # 输出: ['hello', 'world']
- print(re.findall(pattern, text2)) # 输出: ['', 'there']
复制代码
正则表达式优化
正则表达式虽然强大,但如果不注意优化,可能会导致性能问题。以下是一些优化正则表达式的技巧:
1. 避免不必要的捕获:使用非捕获组(?:...)代替捕获组(...),除非确实需要捕获匹配的内容。
2. 使用具体的字符类:使用具体的字符类如[0-9]代替通用的\d,使用[a-zA-Z0-9_]代替\w,这样可以提高匹配速度。
3. 避免贪婪匹配:在可能的情况下,使用非贪婪匹配*?、+?、??、{n,m}?代替贪婪匹配,以减少回溯。
4. 使用原子组和占有量词:使用原子组(?>...)和占有量词?+、*+、++、{n,m}+来限制回溯,提高性能。
5. 避免嵌套量词:避免使用嵌套的量词,如(a+)+,这可能导致灾难性回溯。
6. 使用锚点:使用^和$锚点来限制匹配的位置,减少不必要的尝试。
7. 预编译正则表达式:在Python中,可以使用re.compile()预编译正则表达式,提高重复使用的效率。
避免不必要的捕获:使用非捕获组(?:...)代替捕获组(...),除非确实需要捕获匹配的内容。
使用具体的字符类:使用具体的字符类如[0-9]代替通用的\d,使用[a-zA-Z0-9_]代替\w,这样可以提高匹配速度。
避免贪婪匹配:在可能的情况下,使用非贪婪匹配*?、+?、??、{n,m}?代替贪婪匹配,以减少回溯。
使用原子组和占有量词:使用原子组(?>...)和占有量词?+、*+、++、{n,m}+来限制回溯,提高性能。
避免嵌套量词:避免使用嵌套的量词,如(a+)+,这可能导致灾难性回溯。
使用锚点:使用^和$锚点来限制匹配的位置,减少不必要的尝试。
预编译正则表达式:在Python中,可以使用re.compile()预编译正则表达式,提高重复使用的效率。
让我们看一些优化的例子:
- import re
- import time
- # 未优化的正则表达式
- pattern1 = r".*(\d+).*"
- text = "a" * 1000000 + "12345" + "b" * 1000000
- # 优化的正则表达式
- pattern2 = r".*?(\d+).*"
- # 测试未优化的正则表达式
- start_time = time.time()
- re.search(pattern1, text)
- end_time = time.time()
- print("Unoptimized regex time:", end_time - start_time)
- # 测试优化的正则表达式
- start_time = time.time()
- re.search(pattern2, text)
- end_time = time.time()
- print("Optimized regex time:", end_time - start_time)
- # 预编译正则表达式
- compiled_pattern = re.compile(pattern2)
- start_time = time.time()
- compiled_pattern.search(text)
- end_time = time.time()
- print("Precompiled regex time:", end_time - start_time)
复制代码
常见正则表达式模式
在实际应用中,有一些常见的正则表达式模式被广泛使用。下面列出了一些常见的模式及其用途:
1. - 电子邮件地址:pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
- email = "example@example.com"
- print(re.match(pattern, email)) # 输出: <re.Match object; span=(0, 19), match='example@example.com'>
复制代码 2. - URL:pattern = r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+"
- url = "https://www.example.com"
- print(re.match(pattern, url)) # 输出: <re.Match object; span=(0, 23), match='https://www.example.com'>
复制代码 3. - IP地址:pattern = r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
- ip = "192.168.1.1"
- print(re.match(pattern, ip)) # 输出: <re.Match object; span=(0, 11), match='192.168.1.1'>
复制代码 4. - 日期(YYYY-MM-DD):pattern = r"\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])"
- date = "2023-07-15"
- print(re.match(pattern, date)) # 输出: <re.Match object; span=(0, 10), match='2023-07-15'>
复制代码 5. - 时间(HH:MM:SS):pattern = r"([01]\d|2[0-3]):([0-5]\d):([0-5]\d)"
- time_str = "23:59:59"
- print(re.match(pattern, time_str)) # 输出: <re.Match object; span=(0, 8), match='23:59:59'>
复制代码 6. - HTML标签:pattern = r"<([a-z]+)(?:\s+[^>]*)?>.*?</\1>"
- html = "<div class='example'>Hello</div>"
- print(re.match(pattern, html)) # 输出: <re.Match object; span=(0, 31), match='<div class='example'>Hello</div>'>
复制代码 7. - 中文字符:pattern = r"[\u4e00-\u9fa5]+"
- chinese = "你好,世界"
- print(re.findall(pattern, chinese)) # 输出: ['你好', '世界']
复制代码 8. - 手机号码:pattern = r"1[3-9]\d{9}"
- phone = "13800138000"
- print(re.match(pattern, phone)) # 输出: <re.Match object; span=(0, 11), match='13800138000'>
复制代码 9. - 身份证号码:pattern = r"[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]"
- id_card = "11010519491231002X"
- print(re.match(pattern, id_card)) # 输出: <re.Match object; span=(0, 18), match='11010519491231002X'>
复制代码 10. - 密码强度(至少8个字符,包含大小写字母、数字和特殊字符):pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
- password = "Password123!"
- print(re.match(pattern, password)) # 输出: <re.Match object; span=(0, 12), match='Password123!'>
复制代码
电子邮件地址:
- pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
- email = "example@example.com"
- print(re.match(pattern, email)) # 输出: <re.Match object; span=(0, 19), match='example@example.com'>
复制代码
URL:
- pattern = r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+"
- url = "https://www.example.com"
- print(re.match(pattern, url)) # 输出: <re.Match object; span=(0, 23), match='https://www.example.com'>
复制代码
IP地址:
- pattern = r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
- ip = "192.168.1.1"
- print(re.match(pattern, ip)) # 输出: <re.Match object; span=(0, 11), match='192.168.1.1'>
复制代码
日期(YYYY-MM-DD):
- pattern = r"\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])"
- date = "2023-07-15"
- print(re.match(pattern, date)) # 输出: <re.Match object; span=(0, 10), match='2023-07-15'>
复制代码
时间(HH:MM:SS):
- pattern = r"([01]\d|2[0-3]):([0-5]\d):([0-5]\d)"
- time_str = "23:59:59"
- print(re.match(pattern, time_str)) # 输出: <re.Match object; span=(0, 8), match='23:59:59'>
复制代码
HTML标签:
- pattern = r"<([a-z]+)(?:\s+[^>]*)?>.*?</\1>"
- html = "<div class='example'>Hello</div>"
- print(re.match(pattern, html)) # 输出: <re.Match object; span=(0, 31), match='<div class='example'>Hello</div>'>
复制代码
中文字符:
- pattern = r"[\u4e00-\u9fa5]+"
- chinese = "你好,世界"
- print(re.findall(pattern, chinese)) # 输出: ['你好', '世界']
复制代码
手机号码:
- pattern = r"1[3-9]\d{9}"
- phone = "13800138000"
- print(re.match(pattern, phone)) # 输出: <re.Match object; span=(0, 11), match='13800138000'>
复制代码
身份证号码:
- pattern = r"[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]"
- id_card = "11010519491231002X"
- print(re.match(pattern, id_card)) # 输出: <re.Match object; span=(0, 18), match='11010519491231002X'>
复制代码
密码强度(至少8个字符,包含大小写字母、数字和特殊字符):
- pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
- password = "Password123!"
- print(re.match(pattern, password)) # 输出: <re.Match object; span=(0, 12), match='Password123!'>
复制代码
正则表达式在不同编程语言中的应用
Python中的正则表达式
Python提供了re模块来支持正则表达式操作。re模块中常用的函数有:
• re.match(pattern, string):从字符串的起始位置匹配一个模式,如果匹配成功,返回一个匹配对象;否则返回None。
• re.search(pattern, string):扫描整个字符串,返回第一个成功的匹配对象;如果没有匹配,则返回None。
• re.findall(pattern, string):查找字符串中所有匹配的子串,并返回一个列表。
• re.finditer(pattern, string):查找字符串中所有匹配的子串,并返回一个迭代器。
• re.sub(pattern, repl, string):替换字符串中所有匹配的子串。
• re.split(pattern, string):根据匹配的子串分割字符串。
• re.compile(pattern):编译正则表达式,返回一个正则表达式对象。
让我们看一些Python中使用正则表达式的例子:
- import re
- # 编译正则表达式
- pattern = re.compile(r"\d+")
- # 使用match方法
- text = "123abc"
- match = pattern.match(text)
- if match:
- print("Match found:", match.group()) # 输出: Match found: 123
- # 使用search方法
- text = "abc123def"
- match = pattern.search(text)
- if match:
- print("Match found:", match.group()) # 输出: Match found: 123
- # 使用findall方法
- text = "abc123def456"
- matches = pattern.findall(text)
- print("All matches:", matches) # 输出: All matches: ['123', '456']
- # 使用sub方法
- text = "abc123def456"
- new_text = pattern.sub("NUM", text)
- print("After substitution:", new_text) # 输出: After substitution: abcNUMdefNUM
- # 使用split方法
- text = "abc123def456ghi"
- parts = pattern.split(text)
- print("After splitting:", parts) # 输出: After splitting: ['abc', 'def', 'ghi']
- # 使用finditer方法
- text = "abc123def456ghi"
- for match in pattern.finditer(text):
- print("Match found:", match.group(), "at position", match.span())
- # 输出:
- # Match found: 123 at position (3, 6)
- # Match found: 456 at position (9, 12)
复制代码
JavaScript中的正则表达式
在JavaScript中,正则表达式可以通过两种方式创建:字面量形式和构造函数形式。
字面量形式:/pattern/flags构造函数形式:new RegExp(pattern, flags)
常用的标志(flags)有:
• g:全局匹配,查找所有匹配而非在找到第一个匹配后停止
• i:忽略大小写
• m:多行模式,^和$可以匹配每行的开始和结束
• s:让.匹配包括换行符在内的所有字符
• u:Unicode模式
• y:粘性模式,只在目标字符串的当前位置匹配
JavaScript中常用的正则表达式方法有:
• RegExp.prototype.test(string):测试字符串是否匹配正则表达式,返回true或false。
• RegExp.prototype.exec(string):在字符串中执行匹配搜索,返回结果数组或null。
• String.prototype.match(regexp):在字符串中执行匹配搜索,返回结果数组或null。
• String.prototype.search(regexp):在字符串中查找匹配,返回匹配的索引或-1。
• String.prototype.replace(regexp, replacement):替换字符串中匹配的子串。
• String.prototype.split(regexp):根据匹配的子串分割字符串。
让我们看一些JavaScript中使用正则表达式的例子:
- // 创建正则表达式
- const pattern = /\d+/g;
- // 使用test方法
- const text1 = "123abc";
- console.log(pattern.test(text1)); // 输出: true
- // 使用exec方法
- const text2 = "abc123def456";
- let match;
- while ((match = pattern.exec(text2)) !== null) {
- console.log("Match found:", match[0], "at position", match.index);
- }
- // 输出:
- // Match found: 123 at position 3
- // Match found: 456 at position 9
- // 使用match方法
- const text3 = "abc123def456";
- const matches = text3.match(pattern);
- console.log("All matches:", matches); // 输出: All matches: ['123', '456']
- // 使用search方法
- const text4 = "abc123def";
- const index = text4.search(pattern);
- console.log("Match found at index:", index); // 输出: Match found at index: 3
- // 使用replace方法
- const text5 = "abc123def456";
- const new_text = text5.replace(pattern, "NUM");
- console.log("After substitution:", new_text); // 输出: After substitution: abcNUMdefNUM
- // 使用split方法
- const text6 = "abc123def456ghi";
- const parts = text6.split(pattern);
- console.log("After splitting:", parts); // 输出: After splitting: ['abc', 'def', 'ghi']
复制代码
Java中的正则表达式
Java提供了java.util.regex包来支持正则表达式操作。该包中主要有两个类:Pattern和Matcher。
Pattern类用于编译正则表达式,常用的方法有:
• Pattern.compile(String regex):编译正则表达式,返回一个Pattern对象。
• Pattern.matches(String regex, CharSequence input):编译给定的正则表达式并尝试匹配输入的字符串。
Matcher类用于执行匹配操作,常用的方法有:
• matcher.matches():尝试将整个区域与模式匹配。
• matcher.lookingAt():尝试将区域开头与模式匹配。
• matcher.find():尝试查找与模式匹配的输入序列的下一个子序列。
• matcher.group():返回上一个匹配匹配的输入子序列。
• matcher.start():返回上一个匹配的开始索引。
• matcher.end():返回上一个匹配的结束索引。
• matcher.replaceAll(String replacement):替换所有匹配的子序列。
• matcher.replaceFirst(String replacement):替换第一个匹配的子序列。
此外,String类也提供了一些使用正则表达式的方法:
• String.matches(String regex):判断字符串是否匹配给定的正则表达式。
• String.split(String regex):根据匹配给定的正则表达式来拆分此字符串。
• String.replaceAll(String regex, String replacement):替换所有匹配的子串。
• String.replaceFirst(String regex, String replacement):替换第一个匹配的子串。
让我们看一些Java中使用正则表达式的例子:
- import java.util.regex.*;
- public class RegexExample {
- public static void main(String[] args) {
- // 编译正则表达式
- Pattern pattern = Pattern.compile("\\d+");
-
- // 使用matches方法
- String text1 = "123abc";
- Matcher matcher1 = pattern.matcher(text1);
- System.out.println("Matches: " + matcher1.matches()); // 输出: Matches: false
-
- // 使用lookingAt方法
- Matcher matcher2 = pattern.matcher(text1);
- System.out.println("Looking at: " + matcher2.lookingAt()); // 输出: Looking at: true
-
- // 使用find方法
- String text2 = "abc123def456";
- Matcher matcher3 = pattern.matcher(text2);
- while (matcher3.find()) {
- System.out.println("Match found: " + matcher3.group() + " at position " + matcher3.start());
- }
- // 输出:
- // Match found: 123 at position 3
- // Match found: 456 at position 9
-
- // 使用replaceAll方法
- String text3 = "abc123def456";
- String new_text = matcher3.replaceAll("NUM");
- System.out.println("After substitution: " + new_text); // 输出: After substitution: abcNUMdefNUM
-
- // 使用String的matches方法
- String text4 = "123abc";
- System.out.println("Matches: " + text4.matches("\\d+.*")); // 输出: Matches: true
-
- // 使用String的split方法
- String text5 = "abc123def456ghi";
- String[] parts = text5.split("\\d+");
- System.out.println("After splitting: " + Arrays.toString(parts)); // 输出: After splitting: [abc, def, ghi]
-
- // 使用String的replaceAll方法
- String text6 = "abc123def456";
- String new_text2 = text6.replaceAll("\\d+", "NUM");
- System.out.println("After substitution: " + new_text2); // 输出: After substitution: abcNUMdefNUM
- }
- }
复制代码
其他语言中的正则表达式
除了Python、JavaScript和Java,其他编程语言也提供了对正则表达式的支持。下面简要介绍一些其他语言中的正则表达式使用方法:
C#提供了System.Text.RegularExpressions命名空间来支持正则表达式操作。主要的类是Regex,常用的方法有:
• Regex.IsMatch(string input, string pattern):判断输入字符串是否匹配正则表达式。
• Regex.Match(string input, string pattern):在输入字符串中搜索正则表达式的第一个匹配项。
• Regex.Matches(string input, string pattern):在输入字符串中搜索正则表达式的所有匹配项。
• Regex.Replace(string input, string pattern, string replacement):替换输入字符串中匹配正则表达式的所有子串。
• Regex.Split(string input, string pattern):根据匹配正则表达式的子串分割输入字符串。
- using System;
- using System.Text.RegularExpressions;
- class Program
- {
- static void Main()
- {
- // 使用IsMatch方法
- string text1 = "123abc";
- Console.WriteLine("Matches: " + Regex.IsMatch(text1, @"\d+")); // 输出: Matches: True
-
- // 使用Match方法
- string text2 = "abc123def";
- Match match = Regex.Match(text2, @"\d+");
- if (match.Success)
- {
- Console.WriteLine("Match found: " + match.Value + " at position " + match.Index); // 输出: Match found: 123 at position 3
- }
-
- // 使用Matches方法
- string text3 = "abc123def456";
- MatchCollection matches = Regex.Matches(text3, @"\d+");
- foreach (Match m in matches)
- {
- Console.WriteLine("Match found: " + m.Value + " at position " + m.Index);
- }
- // 输出:
- // Match found: 123 at position 3
- // Match found: 456 at position 9
-
- // 使用Replace方法
- string text4 = "abc123def456";
- string new_text = Regex.Replace(text4, @"\d+", "NUM");
- Console.WriteLine("After substitution: " + new_text); // 输出: After substitution: abcNUMdefNUM
-
- // 使用Split方法
- string text5 = "abc123def456ghi";
- string[] parts = Regex.Split(text5, @"\d+");
- Console.WriteLine("After splitting: " + string.Join(", ", parts)); // 输出: After splitting: abc, def, ghi
- }
- }
复制代码
PHP提供了preg_系列函数来支持正则表达式操作,常用的函数有:
• preg_match(string $pattern, string $subject, array &$matches = null):执行一个正则表达式匹配。
• preg_match_all(string $pattern, string $subject, array &$matches = null):执行一个全局正则表达式匹配。
• preg_replace(string $pattern, string $replacement, string $subject):执行一个正则表达式的搜索和替换。
• preg_split(string $pattern, string $subject):通过一个正则表达式分隔字符串。
- <?php
- // 使用preg_match函数
- $text1 = "123abc";
- if (preg_match("/\d+/", $text1, $matches)) {
- echo "Match found: " . $matches[0] . "\n"; // 输出: Match found: 123
- }
- // 使用preg_match_all函数
- $text2 = "abc123def456";
- if (preg_match_all("/\d+/", $text2, $matches)) {
- echo "All matches: " . implode(", ", $matches[0]) . "\n"; // 输出: All matches: 123, 456
- }
- // 使用preg_replace函数
- $text3 = "abc123def456";
- $new_text = preg_replace("/\d+/", "NUM", $text3);
- echo "After substitution: " . $new_text . "\n"; // 输出: After substitution: abcNUMdefNUM
- // 使用preg_split函数
- $text4 = "abc123def456ghi";
- $parts = preg_split("/\d+/", $text4);
- echo "After splitting: " . implode(", ", $parts) . "\n"; // 输出: After splitting: abc, def, ghi
- ?>
复制代码
Ruby内置了对正则表达式的支持,可以通过/pattern/或Regexp.new(pattern)创建正则表达式对象。常用的方法有:
• Regexp#match(string):在字符串中搜索正则表达式的匹配项。
• String#=~(regexp):在字符串中搜索正则表达式的匹配项,返回匹配的位置或nil。
• String#match(regexp):在字符串中搜索正则表达式的匹配项,返回MatchData对象或nil。
• String#gsub(pattern, replacement):替换字符串中所有匹配的子串。
• String#split(pattern):根据匹配的子串分割字符串。
- # 使用match方法
- text1 = "123abc"
- match_data = /\d+/.match(text1)
- puts "Match found: #{match_data[0]}" if match_data # 输出: Match found: 123
- # 使用=~方法
- text2 = "abc123def"
- position = text2 =~ /\d+/
- puts "Match found at position: #{position}" if position # 输出: Match found at position: 3
- # 使用scan方法
- text3 = "abc123def456"
- matches = text3.scan(/\d+/)
- puts "All matches: #{matches.join(', ')}" # 输出: All matches: 123, 456
- # 使用gsub方法
- text4 = "abc123def456"
- new_text = text4.gsub(/\d+/, "NUM")
- puts "After substitution: #{new_text}" # 输出: After substitution: abcNUMdefNUM
- # 使用split方法
- text5 = "abc123def456ghi"
- parts = text5.split(/\d+/)
- puts "After splitting: #{parts.join(', ')}" # 输出: After splitting: abc, def, ghi
复制代码
Go语言通过regexp包提供对正则表达式的支持。常用的函数有:
• regexp.MustCompile(string) *Regexp:编译正则表达式,返回一个Regexp对象。
• regexp.Compile(string) (*Regexp, error):编译正则表达式,返回一个Regexp对象和可能的错误。
• (*Regexp) MatchString(string) bool:判断字符串是否匹配正则表达式。
• (*Regexp) FindString(string) string:在字符串中查找正则表达式的第一个匹配项。
• (*Regexp) FindAllString(string, int) []string:在字符串中查找正则表达式的所有匹配项。
• (*Regexp) ReplaceAllString(string, string) string:替换字符串中所有匹配的子串。
• (*Regexp) Split(string, int) []string:根据匹配的子串分割字符串。
- package main
- import (
- "fmt"
- "regexp"
- )
- func main() {
- // 编译正则表达式
- pattern := regexp.MustCompile(`\d+`)
- // 使用MatchString方法
- text1 := "123abc"
- fmt.Println("Matches:", pattern.MatchString(text1)) // 输出: Matches: true
- // 使用FindString方法
- text2 := "abc123def"
- match := pattern.FindString(text2)
- fmt.Println("Match found:", match) // 输出: Match found: 123
- // 使用FindAllString方法
- text3 := "abc123def456"
- matches := pattern.FindAllString(text3, -1)
- fmt.Println("All matches:", matches) // 输出: All matches: [123 456]
- // 使用ReplaceAllString方法
- text4 := "abc123def456"
- new_text := pattern.ReplaceAllString(text4, "NUM")
- fmt.Println("After substitution:", new_text) // 输出: After substitution: abcNUMdefNUM
- // 使用Split方法
- text5 := "abc123def456ghi"
- parts := pattern.Split(text5, -1)
- fmt.Println("After splitting:", parts) // 输出: After splitting: [abc def ghi]
- }
复制代码
实战案例
数据验证
正则表达式在数据验证中有着广泛的应用,例如验证电子邮件地址、手机号码、身份证号码等。下面是一些常见的数据验证示例:
- import re
- def validate_email(email):
- pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
- if re.match(pattern, email):
- return True
- else:
- return False
- # 测试
- emails = [
- "example@example.com",
- "user.name@domain.co.uk",
- "user+tag@domain.com",
- "invalid.email@",
- "@invalid.com",
- "invalid@.com"
- ]
- for email in emails:
- print(f"{email}: {validate_email(email)}")
复制代码- import re
- def validate_phone(phone):
- # 中国手机号码验证
- pattern = r"^1[3-9]\d{9}$"
- if re.match(pattern, phone):
- return True
- else:
- return False
- # 测试
- phones = [
- "13800138000",
- "15912345678",
- "12345678901",
- "1380013800",
- "138001380000"
- ]
- for phone in phones:
- print(f"{phone}: {validate_phone(phone)}")
复制代码- import re
- def validate_id_card(id_card):
- # 中国身份证号码验证
- pattern = r"^[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]$"
- if re.match(pattern, id_card):
- return True
- else:
- return False
- # 测试
- id_cards = [
- "11010519491231002X",
- "110105194912310021",
- "11010519491331002X",
- "11010519491232002X",
- "11010519491231002"
- ]
- for id_card in id_cards:
- print(f"{id_card}: {validate_id_card(id_card)}")
复制代码- import re
- def validate_password(password):
- # 密码至少8个字符,包含大小写字母、数字和特殊字符
- pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
- if re.match(pattern, password):
- return True
- else:
- return False
- # 测试
- passwords = [
- "Password123!",
- "password123!",
- "PASSWORD123!",
- "Password123",
- "Pass123!",
- "Password123456!"
- ]
- for password in passwords:
- print(f"{password}: {validate_password(password)}")
复制代码
文本提取和替换
正则表达式在文本提取和替换中也非常有用,例如从HTML中提取链接、从日志中提取特定信息、批量替换文本等。下面是一些示例:
- import re
- def extract_links(html):
- pattern = r'<a\s+(?:[^>]*?\s+)?href="([^"]*)"'
- return re.findall(pattern, html)
- # 测试
- html = """
- <html>
- <body>
- <a href="https://www.example.com">Example</a>
- <a href="https://www.google.com">Google</a>
- <a href="https://www.github.com">GitHub</a>
- </body>
- </html>
- """
- links = extract_links(html)
- for link in links:
- print(link)
复制代码- import re
- def extract_log_info(log):
- # 提取IP地址
- ip_pattern = r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
- ips = re.findall(ip_pattern, log)
-
- # 提取时间戳
- timestamp_pattern = r"\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}"
- timestamps = re.findall(timestamp_pattern, log)
-
- return ips, timestamps
- # 测试
- log = """
- 192.168.1.1 - - [2023-07-15 10:30:45] "GET /index.html HTTP/1.1" 200 1234
- 192.168.1.2 - - [2023-07-15 10:31:12] "POST /login HTTP/1.1" 200 567
- 192.168.1.3 - - [2023-07-15 10:32:01] "GET /dashboard HTTP/1.1" 404 89
- """
- ips, timestamps = extract_log_info(log)
- print("IP addresses:", ips)
- print("Timestamps:", timestamps)
复制代码- import re
- def replace_date_format(text):
- # 将MM/DD/YYYY格式的日期替换为YYYY-MM-DD格式
- pattern = r"\b(\d{2})/(\d{2})/(\d{4})\b"
- replacement = r"\3-\1-\2"
- return re.sub(pattern, replacement, text)
- # 测试
- text = """
- The event will be held on 07/15/2023.
- Another event is scheduled for 12/25/2023.
- The deadline is 01/01/2024.
- """
- new_text = replace_date_format(text)
- print(new_text)
复制代码- import re
- def extract_emails(text):
- pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
- return re.findall(pattern, text)
- # 测试
- text = """
- Contact us at support@example.com for assistance.
- You can also reach out to sales@company.com or info@organization.org.
- For urgent matters, please contact emergency@service.gov.
- """
- emails = extract_emails(text)
- for email in emails:
- print(email)
复制代码
日志分析
正则表达式在日志分析中非常有用,可以帮助我们从大量的日志数据中提取有用的信息。下面是一些示例:
- import re
- from collections import Counter
- def analyze_web_log(log):
- # 提取IP地址、请求方法、URL和状态码
- pattern = r'(\b(?:\d{1,3}\.){3}\d{1,3}\b).*?"(\w+)\s+([^\s]+)\s+HTTP/1.\d"\s+(\d{3})'
- matches = re.findall(pattern, log)
-
- # 统计IP地址访问次数
- ip_counter = Counter(match[0] for match in matches)
-
- # 统计请求方法
- method_counter = Counter(match[1] for match in matches)
-
- # 统计URL访问次数
- url_counter = Counter(match[2] for match in matches)
-
- # 统计状态码
- status_counter = Counter(match[3] for match in matches)
-
- return {
- "ip_counter": ip_counter,
- "method_counter": method_counter,
- "url_counter": url_counter,
- "status_counter": status_counter
- }
- # 测试
- log = """
- 192.168.1.1 - - [15/Jul/2023:10:30:45 +0800] "GET /index.html HTTP/1.1" 200 1234
- 192.168.1.2 - - [15/Jul/2023:10:31:12 +0800] "POST /login HTTP/1.1" 200 567
- 192.168.1.3 - - [15/Jul/2023:10:32:01 +0800] "GET /dashboard HTTP/1.1" 404 89
- 192.168.1.1 - - [15/Jul/2023:10:33:22 +0800] "GET /profile HTTP/1.1" 200 2345
- 192.168.1.2 - - [15/Jul/2023:10:34:05 +0800] "GET /settings HTTP/1.1" 200 1567
- 192.168.1.4 - - [15/Jul/2023:10:35:17 +0800] "GET /index.html HTTP/1.1" 200 1234
- """
- result = analyze_web_log(log)
- print("Top IP addresses:")
- for ip, count in result["ip_counter"].most_common(3):
- print(f"{ip}: {count}")
- print("\nRequest methods:")
- for method, count in result["method_counter"].items():
- print(f"{method}: {count}")
- print("\nTop URLs:")
- for url, count in result["url_counter"].most_common(3):
- print(f"{url}: {count}")
- print("\nStatus codes:")
- for status, count in result["status_counter"].items():
- print(f"{status}: {count}")
复制代码- import re
- from collections import Counter
- def analyze_error_log(log):
- # 提取错误类型和错误消息
- pattern = r'\[(\w+)\]\s+(.+)'
- matches = re.findall(pattern, log)
-
- # 统计错误类型
- error_type_counter = Counter(match[0] for match in matches)
-
- # 统计错误消息
- error_msg_counter = Counter(match[1] for match in matches)
-
- return {
- "error_type_counter": error_type_counter,
- "error_msg_counter": error_msg_counter
- }
- # 测试
- log = """
- [ERROR] Failed to connect to database: Connection timeout
- [WARNING] Disk space is running low: 90% used
- [ERROR] Authentication failed for user: admin
- [INFO] Server started successfully
- [ERROR] Failed to connect to database: Connection timeout
- [WARNING] Memory usage is high: 85% used
- [ERROR] Authentication failed for user: guest
- [ERROR] Failed to connect to database: Connection timeout
- """
- result = analyze_error_log(log)
- print("Error types:")
- for error_type, count in result["error_type_counter"].items():
- print(f"{error_type}: {count}")
- print("\nTop error messages:")
- for error_msg, count in result["error_msg_counter"].most_common(3):
- print(f"{error_msg}: {count}")
复制代码- import re
- from collections import defaultdict
- def analyze_app_log(log):
- # 提取时间戳、日志级别和消息
- pattern = r'(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)'
- matches = re.findall(pattern, log)
-
- # 按小时统计日志数量
- hourly_counts = defaultdict(int)
- for timestamp, level, message in matches:
- hour = timestamp.split(' ')[1].split(':')[0]
- hourly_counts[hour] += 1
-
- # 统计日志级别
- level_counts = defaultdict(int)
- for timestamp, level, message in matches:
- level_counts[level] += 1
-
- # 提取异常信息
- exception_pattern = r'Exception: (.+)'
- exceptions = re.findall(exception_pattern, log)
-
- return {
- "hourly_counts": dict(hourly_counts),
- "level_counts": dict(level_counts),
- "exceptions": exceptions
- }
- # 测试
- log = """
- 2023-07-15 10:30:45 [INFO] Application started
- 2023-07-15 10:31:12 [DEBUG] Loading configuration
- 2023-07-15 10:32:01 [ERROR] Failed to connect to database. Exception: Connection timeout
- 2023-07-15 10:33:22 [INFO] User logged in: admin
- 2023-07-15 10:34:05 [WARNING] Disk space is running low
- 2023-07-15 11:35:17 [ERROR] Authentication failed. Exception: Invalid credentials
- 2023-07-15 11:36:30 [INFO] User logged out: admin
- 2023-07-15 11:37:45 [DEBUG] Cleaning up resources
- """
- result = analyze_app_log(log)
- print("Hourly log counts:")
- for hour, count in sorted(result["hourly_counts"].items()):
- print(f"{hour}:00 - {count} logs")
- print("\nLog level counts:")
- for level, count in result["level_counts"].items():
- print(f"{level}: {count}")
- print("\nExceptions:")
- for exception in result["exceptions"]:
- print(exception)
复制代码
Web爬虫中的文本处理
正则表达式在Web爬虫中也非常有用,可以帮助我们从HTML页面中提取所需的信息。下面是一些示例:
- import re
- import requests
- def extract_links(url):
- # 获取网页内容
- response = requests.get(url)
- html = response.text
-
- # 提取所有链接
- pattern = r'<a\s+(?:[^>]*?\s+)?href="([^"]*)"'
- links = re.findall(pattern, html)
-
- return links
- # 测试
- url = "https://www.example.com"
- links = extract_links(url)
- for link in links[:10]: # 只显示前10个链接
- print(link)
复制代码- import re
- import requests
- def extract_images(url):
- # 获取网页内容
- response = requests.get(url)
- html = response.text
-
- # 提取所有图片
- pattern = r'<img\s+(?:[^>]*?\s+)?src="([^"]*)"'
- images = re.findall(pattern, html)
-
- return images
- # 测试
- url = "https://www.example.com"
- images = extract_images(url)
- for image in images[:10]: # 只显示前10个图片
- print(image)
复制代码- import re
- import requests
- def extract_emails(url):
- # 获取网页内容
- response = requests.get(url)
- html = response.text
-
- # 提取所有电子邮件地址
- pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
- emails = re.findall(pattern, html)
-
- return emails
- # 测试
- url = "https://www.example.com"
- emails = extract_emails(url)
- for email in emails:
- print(email)
复制代码- import re
- import requests
- def extract_phone_numbers(url):
- # 获取网页内容
- response = requests.get(url)
- html = response.text
-
- # 提取所有电话号码(支持多种格式)
- pattern = r"(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})"
- phone_numbers = re.findall(pattern, html)
-
- # 格式化电话号码
- formatted_numbers = []
- for groups in phone_numbers:
- country_code, area_code, prefix, line_number = groups
- if country_code:
- formatted_number = f"+{country_code} ({area_code}) {prefix}-{line_number}"
- else:
- formatted_number = f"({area_code}) {prefix}-{line_number}"
- formatted_numbers.append(formatted_number)
-
- return formatted_numbers
- # 测试
- url = "https://www.example.com"
- phone_numbers = extract_phone_numbers(url)
- for phone_number in phone_numbers:
- print(phone_number)
复制代码- import re
- import requests
- def extract_tables(url):
- # 获取网页内容
- response = requests.get(url)
- html = response.text
-
- # 提取所有表格
- table_pattern = r'<table[^>]*>(.*?)</table>'
- tables = re.findall(table_pattern, html, re.DOTALL)
-
- # 提取表格数据
- all_tables_data = []
- for table in tables:
- # 提取行
- row_pattern = r'<tr[^>]*>(.*?)</tr>'
- rows = re.findall(row_pattern, table, re.DOTALL)
-
- # 提取单元格数据
- table_data = []
- for row in rows:
- # 提取表头或单元格
- cell_pattern = r'<t[hd][^>]*>(.*?)</t[hd]>'
- cells = re.findall(cell_pattern, row, re.DOTALL)
-
- # 清理HTML标签
- cleaned_cells = []
- for cell in cells:
- # 移除HTML标签
- cleaned_cell = re.sub(r'<[^>]+>', '', cell)
- # 移除多余的空白字符
- cleaned_cell = re.sub(r'\s+', ' ', cleaned_cell).strip()
- cleaned_cells.append(cleaned_cell)
-
- if cleaned_cells: # 只添加非空行
- table_data.append(cleaned_cells)
-
- if table_data: # 只添加非空表格
- all_tables_data.append(table_data)
-
- return all_tables_data
- # 测试
- url = "https://www.example.com"
- tables = extract_tables(url)
- for i, table in enumerate(tables):
- print(f"Table {i+1}:")
- for row in table:
- print(row)
- print()
复制代码
正则表达式工具和资源
在学习和使用正则表达式时,有一些工具和资源可以帮助我们提高效率和解决问题。下面是一些常用的正则表达式工具和资源:
在线正则表达式测试工具
1. Regex101(https://regex101.com/)支持多种正则表达式风格(PCRE、Python、Golang、JavaScript)提供详细的解释和调试信息支持代码生成和分享
2. 支持多种正则表达式风格(PCRE、Python、Golang、JavaScript)
3. 提供详细的解释和调试信息
4. 支持代码生成和分享
5. RegExr(https://regexr.com/)直观的界面,支持实时匹配提供正则表达式参考和示例支持保存和分享正则表达式
6. 直观的界面,支持实时匹配
7. 提供正则表达式参考和示例
8. 支持保存和分享正则表达式
9. Debuggex(https://www.debuggex.com/)可视化正则表达式,帮助理解复杂模式支持Ruby、Python、Perl和PCRE风格提供实时匹配和错误提示
10. 可视化正则表达式,帮助理解复杂模式
11. 支持Ruby、Python、Perl和PCRE风格
12. 提供实时匹配和错误提示
13. Regex Pal(https://www.regexpal.com/)简洁的界面,支持实时匹配支持高亮显示匹配结果提供基本的正则表达式参考
14. 简洁的界面,支持实时匹配
15. 支持高亮显示匹配结果
16. 提供基本的正则表达式参考
Regex101(https://regex101.com/)
• 支持多种正则表达式风格(PCRE、Python、Golang、JavaScript)
• 提供详细的解释和调试信息
• 支持代码生成和分享
RegExr(https://regexr.com/)
• 直观的界面,支持实时匹配
• 提供正则表达式参考和示例
• 支持保存和分享正则表达式
Debuggex(https://www.debuggex.com/)
• 可视化正则表达式,帮助理解复杂模式
• 支持Ruby、Python、Perl和PCRE风格
• 提供实时匹配和错误提示
Regex Pal(https://www.regexpal.com/)
• 简洁的界面,支持实时匹配
• 支持高亮显示匹配结果
• 提供基本的正则表达式参考
正则表达式学习资源
1. Regular-Expressions.info(https://www.regular-expressions.info/)全面的正则表达式教程和参考涵盖多种编程语言的正则表达式实现提供大量示例和最佳实践
2. 全面的正则表达式教程和参考
3. 涵盖多种编程语言的正则表达式实现
4. 提供大量示例和最佳实践
5. MDN Web Docs - Regular Expressions(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)Mozilla开发者网络提供的JavaScript正则表达式指南详细的语法说明和示例适合Web开发者学习
6. Mozilla开发者网络提供的JavaScript正则表达式指南
7. 详细的语法说明和示例
8. 适合Web开发者学习
9. Python re Module Documentation(https://docs.python.org/3/library/re.html)Python官方文档中关于re模块的说明详细的API文档和示例适合Python开发者学习
10. Python官方文档中关于re模块的说明
11. 详细的API文档和示例
12. 适合Python开发者学习
13. Java Pattern Class Documentation(https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html)Java官方文档中关于Pattern类的说明详细的语法说明和API文档适合Java开发者学习
14. Java官方文档中关于Pattern类的说明
15. 详细的语法说明和API文档
16. 适合Java开发者学习
Regular-Expressions.info(https://www.regular-expressions.info/)
• 全面的正则表达式教程和参考
• 涵盖多种编程语言的正则表达式实现
• 提供大量示例和最佳实践
MDN Web Docs - Regular Expressions(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
• Mozilla开发者网络提供的JavaScript正则表达式指南
• 详细的语法说明和示例
• 适合Web开发者学习
Python re Module Documentation(https://docs.python.org/3/library/re.html)
• Python官方文档中关于re模块的说明
• 详细的API文档和示例
• 适合Python开发者学习
Java Pattern Class Documentation(https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/regex/Pattern.html)
• Java官方文档中关于Pattern类的说明
• 详细的语法说明和API文档
• 适合Java开发者学习
正则表达式书籍
1. 《精通正则表达式》(Mastering Regular Expressions) - Jeffrey E.F. Friedl正则表达式领域的经典著作深入讲解正则表达式的原理和应用适合希望深入理解正则表达式的读者
2. 正则表达式领域的经典著作
3. 深入讲解正则表达式的原理和应用
4. 适合希望深入理解正则表达式的读者
5. 《正则表达式必知必会》(Regular Expressions Pocket Reference) - Tony Stubblebine简洁实用的正则表达式参考手册包含常用正则表达式模式和示例适合需要快速查阅正则表达式语法的读者
6. 简洁实用的正则表达式参考手册
7. 包含常用正则表达式模式和示例
8. 适合需要快速查阅正则表达式语法的读者
9. 《正则表达式入门经典》(Beginning Regular Expressions) - Andrew Watt适合初学者的正则表达式入门书籍通过实例讲解正则表达式的基本概念和应用适合没有编程基础的读者
10. 适合初学者的正则表达式入门书籍
11. 通过实例讲解正则表达式的基本概念和应用
12. 适合没有编程基础的读者
《精通正则表达式》(Mastering Regular Expressions) - Jeffrey E.F. Friedl
• 正则表达式领域的经典著作
• 深入讲解正则表达式的原理和应用
• 适合希望深入理解正则表达式的读者
《正则表达式必知必会》(Regular Expressions Pocket Reference) - Tony Stubblebine
• 简洁实用的正则表达式参考手册
• 包含常用正则表达式模式和示例
• 适合需要快速查阅正则表达式语法的读者
《正则表达式入门经典》(Beginning Regular Expressions) - Andrew Watt
• 适合初学者的正则表达式入门书籍
• 通过实例讲解正则表达式的基本概念和应用
• 适合没有编程基础的读者
正则表达式库和工具
1. Regex Golf(https://regex.alf.nu/)一个有趣的游戏,通过编写正则表达式来解决特定问题帮助提高正则表达式技能适合有一定基础的读者练习
2. 一个有趣的游戏,通过编写正则表达式来解决特定问题
3. 帮助提高正则表达式技能
4. 适合有一定基础的读者练习
5. Exrex(https://github.com/asciimoo/exrex)一个Python库,可以从正则表达式生成随机字符串帮助测试和理解正则表达式适合需要测试正则表达式的开发者
6. 一个Python库,可以从正则表达式生成随机字符串
7. 帮助测试和理解正则表达式
8. 适合需要测试正则表达式的开发者
9. Regexp::Common(https://metacpan.org/pod/Regexp::Common)一个Perl模块,提供常用的正则表达式模式包含大量预定义的正则表达式适合Perl开发者使用
10. 一个Perl模块,提供常用的正则表达式模式
11. 包含大量预定义的正则表达式
12. 适合Perl开发者使用
13. VerbalExpressions(https://github.com/VerbalExpressions)一个跨平台的库,提供构建正则表达式的流畅接口使正则表达式更易读和维护支持多种编程语言
14. 一个跨平台的库,提供构建正则表达式的流畅接口
15. 使正则表达式更易读和维护
16. 支持多种编程语言
Regex Golf(https://regex.alf.nu/)
• 一个有趣的游戏,通过编写正则表达式来解决特定问题
• 帮助提高正则表达式技能
• 适合有一定基础的读者练习
Exrex(https://github.com/asciimoo/exrex)
• 一个Python库,可以从正则表达式生成随机字符串
• 帮助测试和理解正则表达式
• 适合需要测试正则表达式的开发者
Regexp::Common(https://metacpan.org/pod/Regexp::Common)
• 一个Perl模块,提供常用的正则表达式模式
• 包含大量预定义的正则表达式
• 适合Perl开发者使用
VerbalExpressions(https://github.com/VerbalExpressions)
• 一个跨平台的库,提供构建正则表达式的流畅接口
• 使正则表达式更易读和维护
• 支持多种编程语言
总结与展望
正则表达式是一种强大而灵活的文本处理工具,它能够帮助我们以简洁的方式描述和匹配复杂的文本模式,从而极大地提高工作效率。通过本文的学习,我们从正则表达式的基础概念讲起,逐步深入到高级技巧,通过丰富的实例和详细的代码演示,全面掌握了正则表达式的使用方法。
正则表达式的优势
1. 简洁高效:正则表达式可以用简短的代码描述复杂的文本模式,大大减少了代码量。
2. 跨平台:几乎所有主流编程语言都支持正则表达式,使其成为一种通用的文本处理工具。
3. 功能强大:正则表达式支持复杂的模式匹配,可以处理各种文本处理需求。
4. 灵活多变:正则表达式提供了丰富的元字符和语法,可以灵活地应对各种文本处理场景。
正则表达式的局限性
1. 可读性差:复杂的正则表达式往往难以理解和维护。
2. 性能问题:不当的正则表达式可能导致性能问题,甚至造成”灾难性回溯”。
3. 学习曲线陡峭:正则表达式的语法和概念相对复杂,需要一定的学习成本。
4. 不适合所有场景:对于一些复杂的文本处理任务,可能需要结合其他工具和方法。
正则表达式的最佳实践
1. 保持简洁:尽量使用简单明了的正则表达式,避免不必要的复杂性。
2. 添加注释:对于复杂的正则表达式,添加注释以提高可读性。
3. 测试验证:使用测试工具验证正则表达式的正确性和性能。
4. 考虑替代方案:对于一些复杂的文本处理任务,考虑使用专门的解析器或工具。
正则表达式的未来发展趋势
1. 更好的可读性:未来的正则表达式可能会提供更好的语法和工具,以提高可读性和可维护性。
2. 更高的性能:正则表达式引擎可能会进一步优化,提供更高的匹配效率。
3. 更丰富的功能:正则表达式可能会增加更多的功能和语法,以应对更复杂的文本处理需求。
4. 更好的集成:正则表达式可能会更好地与其他工具和技术集成,提供更全面的文本处理解决方案。
总之,正则表达式是一种强大而灵活的文本处理工具,掌握正则表达式可以帮助我们更高效地处理文本数据,提高工作效率。通过不断学习和实践,我们可以成为正则表达式的高手,轻松应对各种文本处理挑战。 |
|