Python:数据流中查找特定子串的简单算法

本文探讨了在数据流中查找特定子串(如' ')的问题,分析了原始方法(将数据流转换为字符串再搜索)的性能瓶颈,以及学术上的标准方法(如AC自动机、KMP等)的实现复杂性。提出了一种实用的简单算法,利用滑动窗口概念,仅保留最近未搜索的4个缓冲区,并在找到子串时返回,避免了大量内存分配,提高了效率。
摘要由CSDN通过智能技术生成

Python:数据流中查找特定子串的简单算法

目录

问题背景

HTTP的服务器响应包括响应头部(headers)和body。两者的分割标记是连续的2个\r\n,即\r\n\r\n 4字节的序列。现在的问题是,编写一个简单的算法,找到这个headers和body的分界。

定义:什么是数据流?

一个输入Stream提供一个int read(char[] buff, int len)接口的方法。那么,什么是数据流?

介于read API的定义,我们可以把数据流看作潜在无限多个buff的list。其中,每个buff对象至少包含一个字节的数据(但是TCP/IP所约束的read API的规范可能不是这么说的?),也就是说,len(buff)>=1。

C++中有rope的概念,用于描述list<char[]>这一概念。它可以认为是标准string对象的内存存储优化的实现。

原始方法

把list<char[]>拼接为一个string对象,然后调用find/index/search方法。

缺点:每次拼接操作会导致内存分配和memcpy,导致性能开销太大,并有可能引入动态内存分配触发的大延迟,影响实际系统中的可用性。

学术上的标准方法

把要查找的子串模式编译为‘AC自动机’,或者简单一点,挖掘子串内在的冗余重复,使用‘KMP’,或者可以考虑像‘BM’那样从后往前搜索。

缺点:实现复杂性太高,并且在数据流(list<char[]>)这种特殊的数据结构上还要做修改适配。

实用的简单算法

考虑下面的几点:

  1. 对数据流而言,存在‘滑动窗口’的概念,也就是说,子串“\r\n\r\n”只有4个字节,理论上,在上次搜索操作没有找到的情况下,理论上,总是查找最近没有搜索的‘滑动窗口’长度的输入即可。
  2. 问题是,“\r\n\r\n”可能在2个(或更多)buff边界处分割
  3. 那也就是说,我们需要把原始的数据流list<char[]>对象拆分为2+1类:已经被扫描但没有找到的;待扫描的(这一概念相当于一个滑动窗口);以及待处理的。
  4. 待扫描的最多只需要保存4个buff对象(!),我们可以把这部分buff对象简单地拼接为一个string对象,如果找到,直接返回
  5. 如果没有找到,则丢弃第1个buff对象(append到‘已经被扫描但没有找到的’list的最后),算法循环继续

这一算法本质上还是原始的string.find,关键是它为‘数据流’这一限制作了必要的修改,以避免大内存的动态分配开销。 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值