Python-Day09-字符串和正则表达式

Author: Seven_0507
Date: 2019-05-24

本次主要总结字符串的高级用法及正则表达式的使用及练习!
在这里插入图片描述

正则表达式中的一些基本符号如下:
参考《正则表达式30分钟入门教程》

常用的元字符
符号解释示例说明
.匹配除换行符以外的任意字符b.t可以匹配bat / but / b#t / b1t等
\w匹配字母/数字/下划线/汉字b\wt可以匹配bat / b1t / b_t等,但不能匹配b#t
\s匹配空白字符(包括\r、\n、\t等),中文全角空格等love\syou可以匹配love you
\d匹配数字\d\d可以匹配01 / 23 / 99等
\b匹配单词的边界(匹配单词的开始或结束)\bThe\b
^匹配字符串的开始^The可以匹配The开头的字符串
$匹配字符串的结束.exe$可以匹配.exe结尾的字符串
常用的反义代码
\W匹配非字母/数字/下划线/汉字的字符b\Wt可以匹配b#t / b@t等,但不能匹配but / b1t / b_t等
\S匹配非空白字符(包括\r、\n、\t等),中文全角空格等love\Syou可以匹配love#you等,但不能匹配love you
\D匹配非数字\d\D可以匹配9a / 3# / 0F等
\B匹配非单词边界\Bio\B
[^x]匹配除了x以外的任意字符
[^aeiou]匹配除了aeiou这几个字母以外的任意字符
字符类
[ ]匹配来自字符集的任意单一字符(匹配没有预定义元字符的字符集合)[aeiou]可以匹配任一元音字母字符
[^]匹配不在字符集中的任意单一字符[^aeiou]可以匹配任一非元音字母字符
常用的限定符
*匹配0次或多次\w*
+匹配1次或多次\w+
?匹配0次或1次\w?
{N}匹配N次\w{3}
{M,}匹配至少M次\w{3,}
{M,N}匹配至少M次至多N次\w{3,6}
分支条件
|分支,有几种规则若满足任意一种规则都应当成匹配,左到右地测试每个条件匹配到第一个满足的分支结束foo|bar可以匹配foo或者bar
常用分组语法
(exp)匹配exp并捕获到自动命名的组中,用小括号来指定子表达式,就可指定重复次数或其它一些操作(\d{1,3}.){3}匹配1到3位的数字加.,重复3次,(eg:IP地址匹配规则)
(? exp)匹配exp并捕获文本到名称为name的组里,也可以写成(?'name’exp)(?\w+)\w+的组名指定为Word
(?:exp)匹配exp但是不捕获匹配的文本,也不给此分组分配组号
(?=exp)匹配exp前面的位置\b\w+(?=ing)可以匹配I’m dancing中的danc
(?<=exp)匹配exp后面的位置(?<=\bdanc)\w+\b可以匹配I love dancing and reading中的第一个ing
(?!exp)匹配后面不是exp的位置\b((?!abc)\w)+\b可以匹配不包含连续字符串abc的单词
(?<!exp)匹配前面不是exp的位置(?<![a-z])\d{7}匹配前面不是小写字母的七位数字
(?#comment)这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读2[0-4]\d(?#200-249)|250-5|[01]?\d\d?(?#0-199)
懒惰限定符
*?重复任意次,但尽可能少重复a.b ; a.?b将正则表达式应用于aabab,前者会匹配整个字符串aabab,后者会匹配aab和ab两个字符串
+?重复1次或多次,但尽可能少重复
??重复0次或1次,但尽可能少重复
{M,N}?重复M到N次,但尽可能少重复
{M,}?重复M次以上,但尽可能少重复

说明: 如果需要匹配的字符是正则表达式中的特殊字符,那么可以使用\进行转义处理,例如想匹配小数点可以写成\.就可以了,因为直接写.会匹配任意字符;同理,想匹配圆括号必须写成\(和\),否则圆括号被视为正则表达式中的分组。

Python提供了re模块来支持正则表达式相关操作,下面是re模块中的核心函数
参考:GitHub骆昊Python-100-Days

函数说明
compile(pattern, flags=0)编译正则表达式返回正则表达式对象
match(pattern, string, flags=0)用正则表达式匹配字符串 成功返回匹配对象 否则返回None
search(pattern, string, flags=0)搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
split(pattern, string, maxsplit=0, flags=0)用正则表达式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0)用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
fullmatch(pattern, string, flags=0)match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0)查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0)查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge()清除隐式编译的正则表达式的缓存
re.I / re.IGNORECASE忽略大小写匹配标记
re.M / re.MULTILINE多行匹配标记

说明: 上面提到的re模块中的这些函数,实际开发中也可以用正则表达式对象的方法替代对这些函数的使用,如果一个正则表达式需要重复的使用,那么先通过compile函数编译正则表达式并创建出正则表达式对象无疑是更为明智的选择。

1. 字符串和正则表达式练习

1.1 字符串高级操作练习

1.1.1 字符串常用操作

"""
字符串常用操作
"""

import pyperclip

# 原始字符串
print(r'My brother\'s name is \'007\'')
# 转义字符
print('My brother\'s name is \'007\'')
print('*'*80)

# in/ not in/ is开头判断方法
str = 'hello123world'
print('he' in str)
print('her' not in str)
# 字符串是否只包含字母
print(str.isalpha())
print(str[0:5].isalpha())
# 字符串是否只包含字母和数字
print(str.isalnum())
# 字符串是否只包含数字
print(str.isdecimal())
print(str[5:8].isdecimal())
print('*'*80)

# join用法
list = ['床前明月光', '疑是地上霜', '举头望明月', '低头思故乡']
print('-'.join(list))
print('*'*80)

# split()用法
sentence1 = 'You go your way I will go mine'
sentence2 ='www.google.com'
print(sentence1.split()) # 返回一个列表
print(sentence2.split('.',1))
print('*'*80)

# strip()用法
email = '     jackfrued@126.com'
print(email)
print(email.strip())
print(email.rstrip('.com'))
print('*'*80)

# pyperclip模块用法
# 将文本放入系统剪切板中
pyperclip.copy('老虎不发猫你当我病危呀')
# 从系统剪切板获得文本
print(pyperclip.paste())
My brother\'s name is \'007\'
My brother's name is '007'
********************************************************************************
True
True
False
True
True
False
True
********************************************************************************
床前明月光-疑是地上霜-举头望明月-低头思故乡
********************************************************************************
['You', 'go', 'your', 'way', 'I', 'will', 'go', 'mine']
['www', 'google.com']
********************************************************************************
     jackfrued@126.com
jackfrued@126.com
     jackfrued@126
********************************************************************************
老虎不发猫你当我病危呀

1.1.2 字符串倒转

"""
字符串常用操作 - 实现字符串倒转的方法
"""

from io import StringIO


def reverse_str1(str):
    return str[::-1]


def reverse_str2(str):
    if len(str) <= 1:
        return str
    return reverse_str2(str[1:]) + str[0:1]


def reverse_str3(str):
    # StringIO对象是Python中的可变字符串
    # 不应该使用不变字符串做字符串连接操作 因为会产生很多无用字符串对象
    rstr = StringIO()
    str_len = len(str)
    for index in range(str_len - 1, -1, -1):
        rstr.write(str[index])
    return rstr.getvalue()


def reverse_str4(str):
    return ''.join(str[index] for index in range(len(str) - 1, -1, -1))


def reverse_str5(str):
    # 将字符串处理成列表
    str_list = list(str)
    str_len = len(str)
    # 使用zip函数将两个序列合并成一个产生元组的迭代器
    # 每次正好可以取到一前一后两个下标来实现元素的交换
    for i, j in zip(range(str_len // 2), range(str_len - 1, str_len // 2, -1)):
        str_list[i], str_list[j] = str_list[j], str_list[i]
    # 将列表元素连接成字符串
    return ''.join(str_list)


if __name__ == '__main__':
    str = 'I love Python'
    print(str)
    print(reverse_str1(str))
    print('*'*80)
    print(reverse_str2(str))
    print('*'*80)
    print(reverse_str3(str))
    print('*'*80)
    print(reverse_str4(str))
    print('*'*80)
#     print(reverse_str5(str))
I love Python
nohtyP evol I
********************************************************************************
nohtyP evol I
********************************************************************************
nohtyP evol I
********************************************************************************
nohtyP evol I
********************************************************************************

1.2 正则表达式使用练习

1.2.1 验证输入用户名和QQ号是否有效

"""
验证输入用户名和QQ号是否有效并给出对应的提示信息

要求:
用户名必须由字母、数字或下划线构成且长度在6~20个字符之间
QQ号是5~12的数字且首位不能为0
"""

import re


def main():
    username = input('请输入用户名: ')
    qq = input('请输入QQ号: ')
    # match(pattern, string, flags=0)
    # 用正则表达式匹配字符串 成功返回匹配对象 否则返回None
    m1 = re.match(r'^[0-9a-zA-Z_]{6,20}$', username)
    if not m1:
        print('请输入有效的用户名.')
    m2 = re.match(r'^[1-9]\d{4,11}$', qq)
    if not m2:
        print('请输入有效的QQ号.')
    if m1 and m2:
        print('你输入的信息是有效的!')


if __name__ == '__main__':
    main()
请输入用户名: fighting
请输入QQ号: 2148924597
你输入的信息是有效的!

1.2.2 从一段文字中提取出国内手机号码

import re


def main():
    # 创建正则表达式对象 使用了前瞻和回顾来保证手机号前后不应该出现数字
    # compile(pattern, flags=0)编译正则表达式返回正则表达式对象
    pattern = re.compile(r'(?<=\D)(1[38]\d{9}|14[57]\d{8}|15[0-35-9]\d{8}|17[678]\d{8})(?=\D)')
    sentence = '''
    重要的事情说8130123456789遍,我的手机号是13512346789这个靓号,
    不是15600998765,也是110或119,王大锤的手机号才是15600998765。
    '''
    # 查找所有匹配并保存到一个列表中
    # findall(pattern, string, flags=0)查找字符串所有与正则表达式匹配的模式 返回字符串的列表
    mylist = re.findall(pattern, sentence)
    print(mylist)
    print('--------华丽的分隔线--------')
    
    # 通过迭代器取出匹配对象并获得匹配的内容
    # finditer(pattern, string, flags=0)查找字符串所有与正则表达式匹配的模式 返回一个迭代器
    for temp in pattern.finditer(sentence):
        print(temp.group())
    print('--------华丽的分隔线--------')
    
    # 通过search函数指定搜索位置找出所有匹配
    # search(pattern, string, flags=0)搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
    m = pattern.search(sentence)
    while m:
        print(m.group())
        m = pattern.search(sentence, m.end())


if __name__ == '__main__':
    main()
['13512346789', '15600998765', '15600998765']
--------华丽的分隔线--------
13512346789
15600998765
15600998765
--------华丽的分隔线--------
13512346789
15600998765
15600998765

1.2.3 不良内容过滤

"""
不良内容过滤
"""
import re


def main():
    sentence = '你丫是傻叉吗? 我操你大爷的. Fuck you.'
    # sub(pattern, repl, string, count=0, flags=0)用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
    purified = re.sub('[操肏艹]|fuck|shit|傻[比屄逼叉缺吊屌]|煞笔',
                      '*', sentence, flags=re.IGNORECASE)
    print(purified)


if __name__ == '__main__':
    main()
你丫是*吗? 我*你大爷的. * you.

1.2.4 拆分长字符串

import re


def main():
    poem = '窗前明月光,疑是地上霜。举头望明月,低头思故乡。'
    # split(pattern, string, maxsplit=0, flags=0)用正则表达式指定的模式分隔符拆分字符串 返回列表
    sentence_list = re.split(r'[,。, .]', poem)
    while '' in sentence_list:
        sentence_list.remove('')
    print(sentence_list)


if __name__ == '__main__':
    main()
['窗前明月光', '疑是地上霜', '举头望明月', '低头思故乡']
<think>我们使用Python的re模块进行正则表达式匹配。以下是一个详细的指南,包含常见操作代码示例。 正则表达式是一种强大的字符串匹配处理工具。Python通过re模块提供对正则表达式的支持。 主要步骤: 1. 导入re模块 2. 编写正则表达式模式 3. 选择re模块的函数(如match、search、findall等)进行匹配 4. 处理匹配结果 常用函数: - re.match(pattern, string):字符串起始位置匹配,如果起始位置匹配不成功,则返回None。 - re.search(pattern, string): 扫描整个字符串返回第一个成功的匹配。 - re.findall(pattern, string): 返回字符串中所有匹配的子串,以列表形式返回。 - re.finditer(pattern, string): 返回一个迭代器,包含所有匹配对象。 - re.sub(pattern, repl, string): 替换字符串中匹配的子串。 匹配对象(Match object)的方法: - group(): 返回匹配的整个字符串 - groups(): 返回一个包含所有小组字符串的元组 - start(): 返回匹配开始的位置 - end(): 返回匹配结束的位置 - span(): 返回一个元组包含匹配(开始,结束)的位置 编译正则表达式(提高效率): 当同一个正则表达式被多次使用时,可以将其编译成正则表达式对象,以提高效率。 pattern = re.compile(r'pattern') 然后使用 pattern.match(), pattern.search() 等方法。 特殊字符: . 匹配任意字符(除了换行符) ^ 匹配字符串开头 $ 匹配字符串结尾 * 匹配0次或多次 + 匹配1次或多次 ? 匹配0次或1次 {m} 匹配m次 {m,n} 匹配m到n次 [] 字符集,如[abc]匹配a、b、c | 或,如A|B匹配A或B () 分组 \d 匹配数字,等价于[0-9] \D 匹配非数字 \s 匹配空白字符(空格、制表符等) \S 匹配非空白字符 \w 匹配字母数字及下划线,等价于[a-zA-Z0-9_] \W 匹配非字母数字及下划线 注意:在Python中,使用原始字符串(r'string')可以避免转义问题。 下面是一个完整的示例代码,展示各种常见用法:</think># Python 正则表达式字符串匹配详解 在 Python 中使用正则表达式进行字符串匹配主要通过 `re` 模块实现。下面我将详细介绍正则表达式的使用方法常见应用场景。 ## 基础正则表达式匹配 ### 1. 导入 re 模块 ```python import re ``` ### 2. 基本匹配方法 ```python # 示例字符串 text = "Python is a powerful programming language. Python is also versatile." # 1. re.match() -字符串开头匹配 match_result = re.match(r'Python', text) print(match_result) # <re.Match object; span=(0, 6), match='Python'> # 2. re.search() - 搜索整个字符串 search_result = re.search(r'powerful', text) print(search_result) # <re.Match object; span=(10, 17), match='powerful'> # 3. re.findall() - 查找所有匹配项 all_matches = re.findall(r'Python', text) print(all_matches) # ['Python', 'Python'] # 4. re.finditer() - 返回匹配对象迭代器 for match in re.finditer(r'Python', text): print(f"Found '{match.group()}' at position {match.start()}-{match.end()}") # Found 'Python' at position 0-6 # Found 'Python' at position 40-46 # 5. re.fullmatch() - 整个字符串匹配 full_match = re.fullmatch(r'.*', text) print(full_match) # <re.Match object; span=(0, 55), match='Python is a powerful programming language. Python is also > ``` ## 常用正则表达式模式 ### 基本模式示例 ```python # 匹配数字 numbers = re.findall(r'\d+', "Phone: 123-4567, Cell: 987-6543") print(numbers) # ['123', '4567', '987', '6543'] # 匹配单词 words = re.findall(r'\w+', "Hello, world! 2023") print(words) # ['Hello', 'world', '2023'] # 匹配邮箱地址 emails = re.findall(r'[\w\.-]+@[\w\.-]+', "Contact: user@example.com, support@domain.org") print(emails) # ['user@example.com', 'support@domain.org'] # 匹配URL urls = re.findall(r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+', "Visit https://example.com or http://sub.domain.org") print(urls) # ['https://example.com', 'http://sub.domain.org'] ``` ## 高级匹配技巧 ### 1. 分组捕获 ```python # 分组提取 date_text = "2023-10-25, 2024-01-15" matches = re.findall(r'(\d{4})-(\d{2})-(\d{2})', date_text) print(matches) # [('2023', '10', '25'), ('2024', '01', '15')] # 命名分组 pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})' match = re.search(pattern, "Event date: 2023-10-25") if match: print(f"Year: {match.group('year')}, Month: {match.group('month')}, Day: {match.group('day')}") # Year: 2023, Month: 10, Day: 25 ``` ### 2. 非捕获组超前/后行断言 ```python # 非捕获组 (?:...) text = "color: red; color: blue; color: green" colors = re.findall(r'color: (?:red|blue|green)', text) print(colors) # ['color: red', 'color: blue', 'color: green'] # 正向前瞻 (?=...) # 匹配后面跟着"元"的"Python" matches = re.findall(r'Python(?=元)', "Python编程 Python元编程") print(matches) # ['Python'] (只匹配第二个Python) # 负向前瞻 (?!...) # 匹配后面不是"元"的"Python" matches = re.findall(r'Python(?!元)', "Python编程 Python元编程") print(matches) # ['Python'] (只匹配第一个Python) # 正向后顾 (?<=...) # 匹配前面是"元"的"Python" matches = re.findall(r'(?<=元)Python', "元Python编程") print(matches) # ['Python'] # 负向后顾 (?<!...) # 匹配前面不是"元"的"Python" matches = re.findall(r'(?<!元)Python', "元Python 普通Python") print(matches) # ['Python'] (只匹配第二个Python) ``` ### 3. 编译正则表达式 ```python # 编译正则表达式对象(提高性能) pattern = re.compile(r'\b[A-Z][a-z]+\b') # 匹配首字母大写的单词 text = "John Smith and Alice Johnson work at Google." matches = pattern.findall(text) print(matches) # ['John', 'Smith', 'Alice', 'Johnson', 'Google'] ``` ## 字符串操作与正则表达式 ### 1. 字符串替换 ```python # 简单替换 text = "Python 2.7 and Python 3.10" new_text = re.sub(r'Python 2\.7', 'Python 3.x', text) print(new_text) # "Python 3.x and Python 3.10" # 使用函数进行替换 def increment_version(match): version = int(match.group(1)) return f"Python {version + 1}" text = "Python 2, Python 3, Python 4" new_text = re.sub(r'Python (\d)', increment_version, text) print(new_text) # "Python 3, Python 4, Python 5" ``` ### 2. 字符串分割 ```python text = "apple,banana;cherry|date" parts = re.split(r'[,;|]', text) print(parts) # ['apple', 'banana', 'cherry', 'date'] # 保留分隔符 parts = re.split(r'([,;|])', text) print(parts) # ['apple', ',', 'banana', ';', 'cherry', '|', 'date'] ``` ## 实际应用案例 ### 1. 验证输入格式 ```python def validate_email(email): """验证电子邮件地址格式""" pattern = r'^[\w\.-]+@[\w\.-]+\.\w{2,}$' return bool(re.match(pattern, email)) print(validate_email("user@example.com")) # True print(validate_email("invalid.email@")) # False print(validate_email("name@domain.co.uk")) # True ``` ### 2. 提取日志信息 ```python log = """ [2023-10-25 08:30:45] INFO: User 'admin' logged in [2023-10-25 09:15:22] ERROR: Database connection failed [2023-10-25 10:05:33] WARNING: Disk space low """ pattern = r'\[(.*?)\] (\w+): (.*)' for match in re.finditer(pattern, log): timestamp, level, message = match.groups() print(f"{timestamp} | {level:7} | {message}") # 输出: # 2023-10-25 08:30:45 | INFO | User 'admin' logged in # 2023-10-25 09:15:22 | ERROR | Database connection failed # 2023-10-25 10:05:33 | WARNING | Disk space low ``` ### 3. 解析复杂文本 ```python html = """ <div class="product"> <h3>Product A</h3> <p>Price: $19.99</p> <p>Rating: 4.5/5</p> </div> <div class="product"> <h3>Product B</h3> <p>Price: $29.99</p> <p>Rating: 3.8/5</p> </div> """ pattern = r'<div class="product">.*?<h3>(.*?)</h3>.*?<p>Price: \$(.*?)</p>.*?<p>Rating: (.*?)/5</p>' products = re.findall(pattern, html, re.DOTALL) for name, price, rating in products: print(f"Product: {name}, Price: ${price}, Rating: {rating}/5") # 输出: # Product: Product A, Price: $19.99, Rating: 4.5/5 # Product: Product B, Price: $29.99, Rating: 3.8/5 ``` ## 性能优化与最佳实践 1. **预编译正则表达式**:对于重复使用的模式,使用 `re.compile()` 可以提高性能 2. **使用原始字符串**:在模式字符串前加 `r` 前缀(如 `r'\d+'`)避免转义问题 3. **避免贪婪匹配**:在量词后加 `?` 使其变为非贪婪匹配(如 `.*?`) 4. **使用合适的函数**: - 只需检查是否存在匹配:`re.search()` - 需要提取所有匹配:`re.findall()` 或 `re.finditer()` - 需要替换内容:`re.sub()` 5. **考虑使用第三方库**:对于复杂需求,可使用 `regex` 模块(支持更多特性) ```python # 性能比较示例 import timeit # 未编译 def test_uncompiled(): return bool(re.search(r'\d{3}-\d{3}-\d{4}', "Phone: 123-456-7890")) # 预编译 compiled_pattern = re.compile(r'\d{3}-\d{3}-\d{4}') def test_compiled(): return bool(compiled_pattern.search("Phone: 123-456-7890")) # 测试性能 print("未编译:", timeit.timeit(test_uncompiled, number=100000)) print("预编译:", timeit.timeit(test_compiled, number=100000)) # 输出示例(可能): # 未编译: 0.15 seconds # 预编译: 0.08 seconds ``` ## 正则表达式调试工具 1. **在线正则表达式测试器**: - [regex101.com](https://regex101.com/) - [regexr.com](https://regexr.com/) 2. **Python内置调试**: ```python pattern = re.compile(r'(\d{3})-(\d{3})-(\d{4})') print(pattern.pattern) # 输出原始模式字符串 print(pattern.groups) # 输出分组数量 print(pattern.groupindex) # 输出命名分组映射 ``` 3. **使用 re.DEBUG 标志**: ```python re.compile(r'(\d{3})-(\d{3})-(\d{4})', re.DEBUG) # 输出: # SUBPATTERN 1 0 0 # MAX_REPEAT 3 3 # IN # CATEGORY CATEGORY_DIGIT # LITERAL 45 # SUBPATTERN 2 0 0 # MAX_REPEAT 3 3 # IN # CATEGORY CATEGORY_DIGIT # LITERAL 45 # SUBPATTERN 3 0 0 # MAX_REPEAT 4 4 # IN # CATEGORY CATEGORY_DIGIT ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值