告别正则表达式,这个Python库可以快M倍
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了告别正则表达式,这个Python库可以快M倍相关的知识,希望对你有一定的参考价值。
参考技术AFlashText 算法是由 Vikash Singh 于2017年发表的大规模关键词替换算法,这个算法的时间复杂度仅由文本长度(N)决定,算法时间复杂度为O(N)。
而对于正则表达式的替换,算法时间复杂度还需要考虑被替换的关键词数量(M),因此时间复杂度为O(MxN)。
简而言之, 基于FlashText算法的字符串替换比正则表达式替换快M倍以上,这个M是需要替换的关键词数量,关键词越多,FlashText算法的优势就越明显 。
下面就给大家介绍如何在 Python 中基于 flashtext 模块使用 FlashText 算法进行字符串查找和替换,如果觉得对你的项目团队很有帮助,请记得帮作者转发一下哦。
1.准备
开始之前,你要确保Python和pip已经成功安装在电脑上,如果没有,可以访问这篇文章:超详细Python安装指南 进行安装。
(可选1) 如果你用Python的目的是数据分析,可以直接安装Anaconda:Python数据分析与挖掘好帮手—Anaconda,它内置了Python和pip.
(可选2) 此外,推荐大家用VSCode编辑器,它有许多的优点:Python 编程的最好搭档—VSCode 详细指南。
请选择以下任一种方式输入命令安装依赖 :
1. Windows 环境 打开 Cmd (开始-运行-CMD)。
2. MacOS 环境 打开 Terminal (command+空格输入Terminal)。
3. 如果你用的是 VSCode编辑器 或 Pycharm,可以直接使用界面下方的Terminal.
pip install flashtext
2.基本使用
提取关键词
一个最基本的提取关键词的例子如下:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 添加关键词
keyword_processor.add_keyword( \'Big Apple\' , \'New York\' )
keyword_processor.add_keyword( \'Bay Area\' )
# 3. 处理目标句子并提取相应关键词
keywords_found = keyword_processor.extract_keywords( \'I love Big Apple and Bay Area.\' )
# 4. 结果
print(keywords_found)
# [\'New York\', \'Bay Area\']
其中 add_keyword 的第一个参数代表需要被查找的关键词,第二个参数是给这个关键词一个别名,如果找到了则以别名显示。
替换关键词
如果你想要替换关键词,只需要调用处理器的 replace_keywords 函数:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 添加关键词
keyword_processor.add_keyword( \'New Delhi\' , \'NCR region\' )
# 3. 替换关键词
new_sentence = keyword_processor.replace_keywords( \'I love Big Apple and new delhi.\' )
# 4. 结果
print(new_sentence)
# \'I love New York and NCR region.\'
关键词大小写敏感
如果你需要精确提取,识别大小写字母,那么你可以在处理器初始化的时候设定 sensitive 参数:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器, 注意设置大小写敏感(case_sensitive)为TRUE
keyword_processor = KeywordProcessor(case_sensitive= True )
# 2. 添加关键词
keyword_processor.add_keyword( \'Big Apple\' , \'New York\' )
keyword_processor.add_keyword( \'Bay Area\' )
# 3. 处理目标句子并提取相应关键词
keywords_found = keyword_processor.extract_keywords( \'I love big Apple and Bay Area.\' )
# 4. 结果
print(keywords_found)
# [\'Bay Area\']
标记关键词位置
如果你需要获取关键词在句子中的位置,在 extract_keywords 的时候添加 span_info=True 参数即可:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 添加关键词
keyword_processor.add_keyword( \'Big Apple\' , \'New York\' )
keyword_processor.add_keyword( \'Bay Area\' )
# 3. 处理目标句子并提取相应关键词, 并标记关键词的起始、终止位置
keywords_found = keyword_processor.extract_keywords( \'I love big Apple and Bay Area.\' , span_info= True )
# 4. 结果
print(keywords_found)
# [(\'New York\', 7, 16), (\'Bay Area\', 21, 29)]
获取目前所有的关键词
如果你需要获取当前已经添加的所有关键词,只需要调用处理器的 get_all_keywords 函数:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 添加关键词
keyword_processor.add_keyword( \'j2ee\' , \'Java\' )
keyword_processor.add_keyword( \'colour\' , \'color\' )
# 3. 获取所有关键词
keyword_processor.get_all_keywords()
# output: \'colour\': \'color\', \'j2ee\': \'Java\'
批量添加关键词
批量添加关键词有两种方法,一种是通过词典,一种是通过数组:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. (第一种)通过字典批量添加关键词
keyword_dict =
"java" : [ "java_2e" , "java programing" ],
"product management" : [ "PM" , "product manager" ]
keyword_processor.add_keywords_from_dict(keyword_dict)
# 2. (第二种)通过数组批量添加关键词
keyword_processor.add_keywords_from_list([ "java" , "python" ])
# 3. 第一种的提取效果如下
keyword_processor.extract_keywords( \'I am a product manager for a java_2e platform\' )
# output [\'product management\', \'java\']
单一或批量删除关键词
删除关键词也非常简单,和添加类似:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 通过字典批量添加关键词
keyword_dict =
"java" : [ "java_2e" , "java programing" ],
"product management" : [ "PM" , "product manager" ]
keyword_processor.add_keywords_from_dict(keyword_dict)
# 3. 提取效果如下
print(keyword_processor.extract_keywords( \'I am a product manager for a java_2e platform\' ))
# [\'product management\', \'java\']
# 4. 单个删除关键词
keyword_processor.remove_keyword( \'java_2e\' )
# 5. 批量删除关键词,也是可以通过词典或者数组的形式
keyword_processor.remove_keywords_from_dict( "product management" : [ "PM" ])
keyword_processor.remove_keywords_from_list([ "java programing" ])
# 6. 删除了java programing关键词后的效果如下
keyword_processor.extract_keywords( \'I am a product manager for a java_2e platform\' )
# [\'product management\']
3.高级使用
支持额外信息
前面提到在添加关键词的时候第二个参数为其别名,其实你不仅可以指示别名,还可以将额外信息放到第二个参数中:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
kp = KeywordProcessor()
# 2. 添加关键词并附带额外信息
kp.add_keyword( \'Taj Mahal\' , ( \'Monument\' , \'Taj Mahal\' ))
kp.add_keyword( \'Delhi\' , ( \'Location\' , \'Delhi\' ))
# 3. 效果如下
kp.extract_keywords( \'Taj Mahal is in Delhi.\' )
# [(\'Monument\', \'Taj Mahal\'), (\'Location\', \'Delhi\')]
这样,在提取关键词的时候,你还能拿到其他一些你想要在得到此关键词时输出的信息。
支持特殊单词边界
Flashtext 检测的单词边界一般局限于 w [A-Za-z0-9_] 外的任意字符,但是如果你想添加某些特殊字符作为单词的一部分也是可以实现的:
from flashtext import KeywordProcessor
# 1. 初始化关键字处理器
keyword_processor = KeywordProcessor()
# 2. 添加关键词
keyword_processor.add_keyword( \'Big Apple\' )
# 3. 正常效果
print(keyword_processor.extract_keywords( \'I love Big Apple/Bay Area.\' ))
# [\'Big Apple\']
# 4. 将 \'/\' 作为单词一部分
keyword_processor.add_non_word_boundary( \'/\' )
# 5. 优化后的效果
print(keyword_processor.extract_keywords( \'I love Big Apple/Bay Area.\' ))
# []
4.结尾
个人认为这个模块已经满足我们的基本使用了,如果你有一些该模块提供的功能之外的使用需求,可以给 flashtext 贡献代码:
https://github.com/vi3k6i5/flashtext
附 FlashText 与正则相比 查询关键词 所花费的时间之比:
附 FlashText 与正则相比 替换关键词 所花费的时间之比:
这篇文章如果对你有帮助的话,记得转发一下哦。
python爬虫学习记录基本库的使用——正则表达式
正则表达式测试工具:http://tool.oschina.net/regex
1、常见语法
https://www.runoob.com/regexp/regexp-syntax.html
2、match()
用match传入要匹配的字符串以及正则表达式,就可以及检测这个正则表达式是否匹配字符串。
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
print(len(content))
result = re.match('^Hello\\s\\d\\d\\d\\s\\d{4}\\s\\w{10}',content)
print(result)
print(result.group())
print(result.span())
41
<re.Match object; span=(0, 25), match='Hello 123 4567 World_This'>
Hello 123 4567 World_This
(0, 25)
正则表达式^匹配字符串开头,以Hello开头;\\s匹配空白字符;\\d匹配数字,3个\\d匹配123;\\s匹配空格;4567用四个\\d匹配,用{4}来表示匹配4次;紧接一个空白字符,最后用\\w{10}匹配10个字母以及下划线。
(1)匹配目标
如果想从字符串中提取一部分内容,可以使用()把想提取的子字符串括起来。()标记一个子表达式开始和结束的位置,被标记的每个子表达式会一次对应每个分组,调用group()方法传入分组的索引即可获取提取的结果。
(2)贪婪与非贪婪匹配
贪婪匹配:.*
import re
content = 'Hello 123 4567 World_This is a Regex Demo'
result = re.match('^He.*(\\d+).*Demo$',content)
print(result)
print(result.group(1))
<re.Match object; span=(0, 41), match='Hello 123 4567 World_This is a Regex Demo'>
7
.*会尽可能多的匹配字符,因为.*后是\\d+,意思是至少一个数字,没有具体多少个数字,于是就尽可能多的匹配字符,把123456匹配了,只留下一个7.
非贪婪匹配:.*?
import re
content = 'Hello 1234567 World_This is a Regex Demo'
result = re.match('^He.*?(\\d+).*Demo$',content)
print(result)
print(result.group(1))
<re.Match object; span=(0, 40), match='Hello 1234567 World_This is a Regex Demo'>
1234567
当.*?陪陪到hello后的空白字符,再往后就是数字,\\d+恰好可以匹配,.*?就不再匹配了,交给\\d+匹配后面的数字,1234567
尽量使用.*?,避免匹配结果出现缺失
但如果匹配的结果出现在字符串结尾,使用.*尽可能匹配多的内容
import re
content = 'http://weibo.com/comment/kEraCN'
result1 = re.match('http.*?comment/(.*?)',content)
result2 = re.match('http.*?comment/(.*)',content)
print('result1:',result1.group(1))
print('result2:',result2.group(1))
result1:
result2: kEraCN
(3)修饰符
正则表达式可以包含一些可选标志修饰符来控制匹配模式。修饰符被指定为一个可选的标志。
import re
content ='''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\\d+).*?Demo$',content)
print(result.group(1))
AttributeError: 'NoneType' object has no attribute 'group'
.匹配的是除换行符之外的任意字符,遇到换行时.*?就不能匹配了,这是需要添加re.S修饰错误。这个可以匹配节点之间的换行。
import re
content ='''Hello 1234567 World_This
is a Regex Demo
'''
result = re.match('^He.*?(\\d+).*?Demo$',content,re.S)
print(result.group(1))
此时又可以输出1234567。
re.I 匹配对大小写不敏感
re.L 做本地化匹配
re.M 多行匹配,影响^,$
re.S 使.匹配包括换行在内的所有字符
re.U 根据unicode字符集解析字符,这个标志影响\\w,\\W,\\b,\\B
re.X 通过给与更灵活的格式以便将正则表达式写得更易于理解
(4)转义匹配
用\\来转义特殊字符
import re
content ='(百度)www.baidu.com'
result = re.match('\\(百度\\)www\\.baidu\\.com',content)
print(result)
<re.Match object; span=(0, 17), match='(百度)www.baidu.com'>
3、search()
match是从字符串开头开始匹配。search是在匹配时会扫描整个字符串,返回第一个成功匹配的结果,正则可以使字符串的一部分。
import re
content = 'Extra string Hello 1234567 World_This is a Regex Demo Extra strings'
result = re.search('Hello.*?(\\d+).*?Demo',content)
print(result)
print(result[1])
<re.Match object; span=(13, 53), match='Hello 1234567 World_This is a Regex Demo'>
1234567
4、findall()
获取匹配正则表达式的所有内容,如果有返回结果,就是列表类型,需要遍历来一次获取每组内容。
5、sub()
可以修改文本
import re
content = '54K54yr5oiR54ix5L2g'
content = re.sub('\\d+','',content)
print(content)
结果如下
KyroiRixLg
第一个参数\\d+来匹配所有数字,第二个参数代表被替换成的字符串,第三个参数是原字符串。
可以通过sub方法处理,再用findall方法提取。
6、compile()
可以把正则字符串编译成正则表达式对象
import re
content1 = '2016-12-15 12:00'
content2 = '2016-12-17 12:55'
content3 = '2016-12-22 13:21'
pattern = re.compile('\\d{2}:\\d{2}')
result1 = re.sub(pattern,'',content1)
result2 = re.sub(pattern,'',content2)
result3 = re.sub(pattern,'',content3)
print(result1,result2,result3)
2016-12-15 2016-12-17 2016-12-22
我们想要把三个日期中的时间去掉,可以借助sub方法,把正则表达式用compile编译成一个对象pattern,最后使用sub方法替换即可。
以上是关于告别正则表达式,这个Python库可以快M倍的主要内容,如果未能解决你的问题,请参考以下文章