Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python 字符串子串定位性能比较

Python 字符串子串定位性能比较

原创
作者头像
邵靖
修改于 2017-09-29 06:48:26
修改于 2017-09-29 06:48:26
4.1K00
代码可运行
举报
文章被收录于专栏:邵靖的专栏邵靖的专栏
运行总次数:0
代码可运行

项目最近遇到一个需求:

  1. 给定一组文本文件,每个文本包含若干行,每一行是一条数据记录;
  2. 每一行各字段按照如下方式排布,首先是n个metafield字段,紧接着是最多4个keyfield字段,然后是m个valuefield字段,每个字段用"|"分隔,key从哪个字段开始以及key有几个字段已知metafield_1|metafield_2|...|metafield_n|keyfield_1|...|keyfield_4|valuefield_1|valuefield_2|....|valuefield_m
  3. 任务是对这组文件按keyfields_string除重

除开业务细节,这个任务本质是:

  1. 遍历每个文件的每一行;
  2. 然后截取出keyfield字段集合;
  3. 然后对其进行重复判断;
  4. 最后按照判断结果决定本行是否插入新文件中。

Python很适合完成这种文本处理任务,字符串重复判断这种任务可以使用dict来完成,本文中不做深入探讨。本文想探讨的是在给定了key字段在字段列表中开始下标和key字段个数后,如何在整行字符串中定位到key字符串的起始位置。简而言之,就是确定keyfield_1前一个和keyfield_p后一个“|”字符的位置。

解决这个问题,我想到了三种思路:

  1. 将整个字符串用"|"分割(split),并根据key字段的下标计算首尾两个"|"的位置;
  2. 使用(index/find)函数,通过设置搜索起始位置,按顺序逐个查找"|"字符的位置,直到找到目标“|”位置
  3. 先通过正则表达式或字符串遍历的方式查找出所有"|"的位置生成list,然后根据key字段下标找到目标“|”位置

有同学会说方法1既然每个字段都已经分割开了,将其按照顺序组合就能得到keyfields_string,为何还要查找“|”字符的位置,我想说在这里只是比较在字符串中查找子串的各种方法。

针对以上三个思路,我一共有七种实现,后面会对比其效率:

字符串分割思路

Split

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def get_pos_split(line, key_start):
    pos = 0
    tmp_line_list = line.split('|')
    for i in xrange(key_start):
        if i >= len(tmp_line_list):
            return len(line)
        pos += len(tmp_line_list[i]) + 1
    return pos

逐个查找子串位置思路

这个思路我写了三种方法,分别用 index/find来实现,需要注意的是,index函数在未找到子串的情况下会抛出ValueError错误,需要用try except处理,而find在找不到子串的情况下返回-1,两者效率基本一致。并且在查找下一个子串的方式上有少许不同,一种是当找到当前子串位置后,记录下该位置,然后下一次从本次找到的位置+1开始查找,另一种是每找到一个子串,就去掉前缀部分,然后下一次在剩下的字符串中查找。

Find

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#使用find查找,记录查找位置,下一次从本次找到的位置+1开始查找
def get_pos_find(line, key_start):
    if key_start == 0: 
        return 0
    pos = line.find('|')
    while pos >= 0 and key_start > 1:
        pos = line.find('|', pos+1)
        key_start -= 1
    return len(line) if pos == -1 else pos+1

Index

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#使用index查找,记录查找位置,下一次从本次找到的位置+1开始查找
def get_pos_index(line, key_start):
    pos = 0
    for i in xrange(key_start):
        try:  
            pos = line.index('|', pos+1)
        except ValueError,e:
            return len(line)
    return 0 if pos == 0 else pos+1

Index Cut

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#使用index查找,每次找到第一个子串后,就去掉前缀部分,拷贝后缀部分,后续不断在后缀部分查找
def get_pos_index_2(line, key_start):
    tmp_line = line
    pos = 0
    for i in xrange(key_start):
        try:
            pos += tmp_line.index('|')+1
            tmp_line = tmp_line[tmp_line.index('|')+1:]
        except ValueError, e:
            return len(line)
    return pos

定位所有子串思路

针对这个思路,分别使用正则表达式模块,列表推导式以及lambda、map、filter组合方式实现。

  • 正则表达式 re.finditer 方法会返回字符串中所有子串位置的迭代器
  • 列表推倒式将遍历整个字符串并输出子串位置的列表
  • 组合复杂函数的方法,首先用map扫描字符串中所有匹配子串的位置,不匹配的输出-1,再通过filter与lambda函数结合的方式在刚才的结果中过滤掉-1元素

Regex

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#通过正则表达式re模块查找匹配所有子串位置
def get_pos_re(line, key_start):
    pos_idx = [p.start() for p in re.finditer('\|', line)]
    return 0 if key_start == 0 else (pos_idx[key_start-1]+1 if key_start <= len(pos_idx) else len(line))

LC

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#通过列表推导式(list comprehensions)实现
def get_pos_lc(line, key_start):
    pos_idx = [i for i, x in enumerate(line) if x == '|']
    return 0 if key_start == 0 else (pos_idx[key_start-1]+1 if key_start <= len(pos_idx) else len(line))

Filter

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#通过 lambda、map、filter 组合实现
def get_pos_filter(line, key_start):
    def func_in(t):
        return t[0] if t[1] == '|' else -1
    pos_idx = filter(lambda x: x!=-1, map(func_in, enumerate(line)))
    return 0 if key_start == 0 else (pos_idx[key_start-1]+1 if key_start <= len(pos_idx) else len(line))

测试对比

首先,测试在相同单条记录,不同的记录条数条件下,各种方法的耗时,结果如上图所示。

然后,测试在记录条数一定,不同记录长度条件下,各种方法耗时,结果如上图所示。

第三,测试在相同单条记录,相同记录条数情况下取不同位置的字段各种方法耗时,结果如上图所示。

结论

通过测试对比可以看到,字符串分割逐个查找子串位置的思路在总体上都比定位所有子串位置的思路效率更高。

逐个查找子串位置思路中通过find和index定位子串位置的效率最高,拆分子串的方式次之。影响性能的因素是单条记录长度以及所需要查找的字段位置。

字符串分割,影响性能的因素是单条记录长度以及所需要查找的字段位置。

定位所有子串因为要定位到每个字段的位置,相当于扫描全数据,所以效率最低。在这个思路的三种方法中,正则表达式的实现效率最高,其他两种效率都很差。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Python教程(7)——一文弄懂Python字符串操作(上)
在计算机编程中,字符串是由字符组成的字节序列。在Python中,字符串是表示文本数据的数据类型,由一系列 Unicode 字符组成。字符串可以包含字母、数字、标点符号、空格以及其他特殊字符。实际工作当中,接触最多的可能就是字符串了。
一点sir
2023/08/15
2930
Python “字符串操作” ——Python面试100道实战题目练习,巩固知识、检查技术、成功就业
题目1:在Python中,如何获取字符串"Hello, World!"中第一个字符? A. "Hello, World!"[0] B. "Hello, World!"[1] C. "Hello, World!"[-1] D. "Hello, World!"[len("Hello, World!")]
小白的大数据之旅
2024/11/20
4150
Python “字符串操作” ——Python面试100道实战题目练习,巩固知识、检查技术、成功就业
算法:字符串
在示例代码中,str是一个字符串的变量名称,hello world则是该字符串的值,字符串的长度为11,该字符串的表示如下图所示:
用户3578099
2022/03/15
2.8K0
算法:字符串
Python内置数据结构之字符串
字符串 今天跟大家来说一说Python中的字符串数据结构。 上文回顾 让我们回顾一下可变类型及不可变类型: 不可变数据类型:str、int、tuple 可变数据类型:dict、list 今天讲解的
1846122963
2018/03/09
1.6K0
Python内置数据结构之字符串
003. 无重复字符的最长子串 | Leetcode题解
题目要求连续, 我们考虑使用滑动窗口。而这道题就是窗口大小不固定的滑动窗口题目,然后让我们求满足条件的窗口大小的最大值,这是一种非常常见的滑动窗口题目。
苏南
2020/12/16
5480
003. 无重复字符的最长子串 | Leetcode题解
python字符串操作
本篇文章将介绍python的字符串操作,更多内容请参考:python学习指南 一、查看帮助文档 在学习编程语言过程中,不管是python语言还是其它语言时我们都应该学会查看API文档,查看帮助信息,以便我们进行开发使用。 学习python查看文档有两种方式: 下载官方的API文档进行查阅,官方地址:python官方地址 可以在本地搭建好的环境中,进入命令窗口并切换到python环境,使用dir()和help()方法函数进行查看,比如,我想查看str字符串中有哪些属性和方法,使用dir(str)命
用户1174963
2018/01/17
1K0
生物信息学算法之Python实现|Rosalind刷题笔记:009 查找DNA中的motif
在字符串中查找子串是一个常见问题。子串在字符串中可能是唯一的,比如特定的基因序列;也有可能有多个拷贝,比如基因组中的重复序列。这些重复序列可能相同,可能有微小区别。本题中重复子串完全相同,可以简单地通过 Python 的find()函数来查找,如果重复子串不完全相同并且符合某种模式,则可以用正则表达式模块re来处理。
简说基因
2020/12/15
8410
C++实现字符串的分割和替换
代码主要说明: (1)tmp.find(target):查找子串第一次出现的下标; (2)string::npos:表示未查找到子串时返回的数值。MSDN中规定,其值定义如下:static const size_type npos = -1;,转换为无符号整型unsignned int表示的是string所能容纳的最大字符数。 (3)string::size_type (由字符串配置器 allocator 定义) 描述的是 string的size,故需为无符号整数型别。因为字符串配置器缺省以类型size_t 作为 size_type。
恋喵大鲤鱼
2019/02/22
2.9K0
C++实现字符串的分割和替换
代码主要说明: (1)tmp.find(target):查找子串第一次出现的下标; (2)string::npos:表示未查找到子串时返回的数值。MSDN中规定,其值定义如下:static const size_type npos = -1;,转换为无符号整型unsignned int表示的是string所能容纳的最大字符数。 (3)string::size_type (由字符串配置器 allocator 定义) 描述的是 string的size,故需为无符号整数型别。因为字符串配置器缺省以类型size_t 作为 size_type。
恋喵大鲤鱼
2018/08/03
9530
实用!Python文本处理与字符串函数:轻松操纵文本数据
在Python中,我们可以使用丰富的文本处理和字符串函数来轻松操纵文本数据。下面介绍一些常用的方法和函数,以及它们的用法和示例。
用户1289394
2024/02/02
2510
实用!Python文本处理与字符串函数:轻松操纵文本数据
JavaScript 字符串
toString() 方法,返回一个表示该对象的字符串,可以将所有的数据都转换为字符串,但是要排除掉 null 和 undefined
Nian糕
2018/08/21
7500
JavaScript 字符串
【自然语言处理】NLP入门(六):1、正则表达式与Python中的实现(6):字符串常用方法:find()、rfind()、index()、rindex()、count()、replace()
【自然语言处理】NLP入门(一):1、正则表达式与Python中的实现(1):字符串构造、字符串截取
Qomolangma
2024/07/30
1570
【自然语言处理】NLP入门(六):1、正则表达式与Python中的实现(6):字符串常用方法:find()、rfind()、index()、rindex()、count()、replace()
Python字符串
(2)取字符串中的字符,如果从前往后取,第一个字符下标为0,逐一加一;如果从后往前取,最后一个下标是-1,往前逐一减一;
小雨coding
2020/07/09
9640
Python字符串
Python实战之字符串和文本处理
「 傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波」
山河已无恙
2023/01/30
1.2K0
字符串-后缀树和后缀数组详解
首先理解后缀的概念,后缀(suffix)即从某个位置开始到末尾的一个子串。例如字符串 ,它的五个后缀为 、 、 、 、 。
唔仄lo咚锵
2021/12/31
5.3K0
字符串-后缀树和后缀数组详解
python 字符串方法大全
字符串还支持两种类型的字符串格式化的,一个提供了很大程度的灵活性和定制(见str.format(), 格式化字符串的语法和自定义字符串格式化)和其他基于C printf风格的格式,处理范围较窄的类型,是稍硬使用正确,但对于它可以处理的情况(printf样式的字符串格式)通常更快。
用户7886150
2021/01/10
1.6K0
Python:正则表达式re模块
我们在昨天的案例里实际上省略了第3步,也就是"取"的步骤。因为我们down下了的数据是全部的网页,这些数据很庞大并且很混乱,大部分的东西使我们不关心的,因此我们需要将之按我们的需要过滤和匹配出来。
Lansonli
2021/10/09
4380
python数据类型-字符串
哈喽大家好!歪小王又来分享了,今天开始,我将以一种幽默有趣的方式,跟大家一起重温下python基础
歪小王
2024/04/22
1270
python数据类型-字符串
hive字符串函数
hive字符串函数 1. 字符串长度函数:length 语法: length(string A) 返回值: int 说明:返回字符串A的长度 举例:hive> select length('abcedfg') from lxw_dual; 7 2. 字符串反转函数:reverse 语法: reverse(string A) 返回值: string 说明:返回字符串A的反转结果 举例: hive> select reverse(abcedfg') from lxw_dual; gfdecba 3. 字符串连接
学到老
2018/03/16
6.6K0
Python 正则表达式
简介 正则表达式(regular expression)是可以匹配文本片段的模式。最简单的正则表达式就是普通字符串,可以匹配其自身。比如,正则表达式 ‘hello’ 可以匹配字符串 ‘hello’。
小莹莹
2018/04/18
8530
Python 正则表达式
相关推荐
Python教程(7)——一文弄懂Python字符串操作(上)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档