go源码分析:strings包

主要介绍strings包中的 strings.go/search.go/replace.go

string.go中主要介绍Index函数,该函数寻找s中第一次出现substr的位置,返回position或-1:

基本代码如下:

  1 func Index(s, substr string) int {
  2     n := len(substr)
  3     switch {
  4      ...
  5     case n <= bytealg.MaxLen:
  6         // Use brute force when s and substr both are small
  7         if len(s) <= bytealg.MaxBruteForce {
  8             return bytealg.IndexString(s, substr)
  9         }
 10         c := substr[0]
 11         i := 0
 12         t := s[:len(s)-n+1]
 13         fails := 0
 14         for i < len(t) {
 15             if t[i] != c {
 16                 // IndexByte is faster than bytealg.IndexString, so use it as long as
 17                 // we‘re not getting lots of false positives.
 18                 o := IndexByte(t[i:], c)
 19                 if o < 0 {
 20                     return -1
 21                 }
 22                 i += o
 23             }
 24             if s[i:i+n] == substr {
 25                 return i
 26             }
 27             fails++
 28             i++
 29             // Switch to bytealg.IndexString when IndexByte produces too many false positives.
 30             if fails > bytealg.Cutover(i) {
 31                 r := bytealg.IndexString(s[i:], substr)
 32                 if r >= 0 {
 33                     return r + i
 34                 }
 35                 return -1
 36             }
 37         }
 38         return -1
 39     }
 40     c := substr[0]
 41     i := 0
 42     t := s[:len(s)-n+1]
 43     fails := 0
 44     for i < len(t) {
 45         if t[i] != c {
 46             o := IndexByte(t[i:], c)
 47             if o < 0 {
 48                 return -1
 49             }
 50             i += o
 51         }
 52         if s[i:i+n] == substr {
 53             return i
 54         }
 55         i++
 56         fails++
 57         if fails >= 4+i>>4 && i < len(t) {
 58             // See comment in ../bytes/bytes_generic.go.
 59             j := indexRabinKarp(s[i:], substr)
 60             if j < 0 {
 61                 return -1
 62             }
 63             return i + j
 64         }
 65     }
 66     return -1
 67 }
 68
 69
 70 func indexRabinKarp(s, substr string) int {
 71     // Rabin-Karp search
 72     hashss, pow := hashStr(substr)
 73     n := len(substr)
 74     var h uint32
 75     for i := 0; i < n; i++ {
 76         h = h*primeRK + uint32(s[i])
 77     }
 78     if h == hashss && s[:n] == substr {
 79         return 0
 80     }
 81     for i := n; i < len(s); {
 82         h *= primeRK
 83         h += uint32(s[i])
 84         h -= pow * uint32(s[i-n])
 85         i++
 86         if h == hashss && s[i-n:i] == substr {
 87             return i - n
 88         }
 89     }
 90     return -1
 91
 92 }
 93
 94 func hashStr(sep string) (uint32, uint32) {
 95    hash := uint32(0)
 96    for i := 0; i < len(sep); i++ {
 97       hash = hash*primeRK + uint32(sep[i])
 98    }
 99    var pow, sq uint32 = 1, primeRK
100    for i := len(sep); i > 0; i >>= 1 {
101       if i&1 != 0 {
102          pow *= sq
103       }
104       sq *= sq
105    }
106    return hash, pow
107 }

  可以看到在substr较短的情况下使用了暴力匹配,否则使用rabin-karp算法进行比较,以下对rabin-karp以及golang的实现方式进行简要总结:

1. Rabin-Karp算法类似于暴力匹配,假设A为s中即将于substr进行比较的字符串,传统方法需要将A中所有的字符与substr一一比较来判断两者是否相等,这太耗时了;

2. 为此我们将上述比较替换成比较A与substr的hash值,这样就将字符串匹配简化为整形的判等。为了减小运算量,这里希望对于一个长字符串的hash值能够尽可能短,但实际上不能指望长字符串有短hash值,而且当这个值很大的时候可能溢出, 这个时候就需要用求余来解决。

3. hash以及hash求余都会有hash值碰撞的问题,所以最后要把hash值相等的两个串再逐个匹配一下确认其相等。golang在实现上实际上使用了uint32大小的限制,隐式地取了余数。

4. 这里值得一提的是golang在hash方法的选择上是很特殊的。它使用了一个特殊的hash函数(s[0]*pow(PrimeRK,n-1)+s[1]*pow(PrimeRK,n-2)+...+s[n-1]),使得 hash[i+1:i+n+1] = hash[i:i+n]*PrimeRK+s[i+n+1]-s[i]*pow(PrimeRK,n) 也就是说存在hash[i+1:i+n+1]=f(hash[i:i+n]) 的关系,即A的下一个待匹配项能够迅速由A计算得到,大大加快了计算hash[i+1:i+n+1]的速度。

===未完待续======

原文地址:https://www.cnblogs.com/souther-blog/p/10366952.html

时间: 2024-10-23 20:11:20

go源码分析:strings包的相关文章

从源码分析StringUtils包

今天用到StringUtils.join方法,闲来无聊,看了下源码 当然不可能自己分析,你傻啊,在这里推荐一个别人分析的; http://blog.csdn.net/baidu_31071595/article/details/51320622 首先导包 import org.apache.commons.lang3.StringUtils; 我在这里调用的是StringUtils.join方法 public static String join(Object[] array, char sep

区块链教程以太源码分析accounts包简介

accounts包实现了eth客户端的钱包和账户管理.账号的数据结构:typeAccount struct { Address common.Address json:"address" // Ethereum account addressderived from the key URLURL json:"url" // Optional resource locator within a backend }钱包interface,是指包含了一个或多个账户的软件钱

Sharding-Proxy 源码分析

目录 Sharding-Proxy 源码分析 Sharding-Proxy 包结构 Sharding-Proxy 启动流程 Sharding-Proxy 请求接入 MySQL 报文解析器 MySQL 执行器 MySQLComQueryPacketExecutor 执行流程 MySQLComStmtExecuteExecutor 执行流程 Sharding-Proxy 消息处理 Sharding-Proxy 源码分析 在看 Sharding-Proxy 源码之前,强烈建议先阅读一直官网的两篇文章:

JDK源码分析之concurrent包(一) -- Executor架构

Java5新出的concurrent包中的API,是一些并发编程中实用的的工具类.在高并发场景下的使用非常广泛.笔者在这做了一个针对concurrent包中部分常用类的源码分析系列.本系列针对的读者是已经对并发包中的Executor框架和工具类有所了解并懂得如何使用的人群,如果对并发包还不了解的朋友,请先做些了解.网上对这方面的讲述有丰富的资源. 本篇博文是第一期,首先对Executor架构做一个概述.这里只简单介绍接口和类的继承.使用关系. 盗用一张类图来描述结构: 解析: Executor是

Java多线程 -- JUC包源码分析11 -- ThreadPoolExecutor源码分析

在JUC包中,线程池部分本身有很多组件,可以说是前面所分析的各种技术的一个综合应用.从本文开始,将综合前面的知识,逐个分析线程池的各个组件. -Executor/Executors -ThreadPoolExecutor使用介绍 -ThreadPoolExecutor实现原理 –ThreadPoolExecutor的中断与优雅关闭 shutdown + awaitTermination –shutdown的一个误区 Executor/Executors Executor是线程池框架最基本的几个接

[python] 词云:wordcloud包的安装、使用、原理(源码分析)、中文词云生成、代码重写

词云,又称文字云.标签云,是对文本数据中出现频率较高的“关键词”在视觉上的突出呈现,形成关键词的渲染形成类似云一样的彩色图片,从而一眼就可以领略文本数据的主要表达意思.常见于博客.微博.文章分析等. 除了网上现成的Wordle.Tagxedo.Tagul.Tagcrowd等词云制作工具,在python中也可以用wordcloud包比较轻松地实现(官网.github项目): from wordcloud import WordCloud import matplotlib.pyplot as pl

Spring IoC 源码分析 (基于注解) 之 包扫描

在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫描的过滤规则.那我们今天就来看下包扫描的具体过程. 还是先看下面的代码: AnnotationConfigApplicationContext类 //该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中 public AnnotationConf

docker 源码分析 一(基于1.8.2版本),docker daemon启动过程;

最近在研究golang,也学习一下比较火的开源项目docker的源代码,国内比较出名的docker源码分析是孙宏亮大牛写的一系列文章,但是基于的docker版本有点老:索性自己就git 了一下最新的代码研读: docker是c/s的架构,分为docker client 和 docker daemon,client端发送命令,daemon端负责完成client发送过来的命令(如获取和存储镜像.管理容器等).两者之间可以通过TCP,HTTP和UNIX SOCKET来进行通信: docker的启动入口

Beego源码分析(转)

摘要 beego 是 @astaxie 开发的重量级Go语言Web框架.它有标准的MVC模式,完善的功能模块,和优异的调试和开发模式等特点.并且beego在国内企业用户较多,社区发达和Q群,文档齐全,特别是 @astaxie 本人对bug和issue等回复和代码修复很快,非常敬业.beego框架本身模块众多,无法简单描述所有的功能.我简单阅读了源码,记录一下beego执行过程.官方文档已经图示了beego执行过程图,而我会比较详细的解释beego的源码实现. beego 是 @astaxie 开

手机自动化测试:appium源码分析之bootstrap一

手机自动化测试:appium源码分析之bootstrap一 前言: poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.poptest推出手机自动化测试的课程,讲解appuim的实际应用,培训全程用商业项目,   大家可以加qq群进行交流:195983133 开源的项目最大的好处是可以获得源代码,我们可以在源代码的基础上进行修改代码,编译,开发出符合我们要求的项目.如果想要做到可以修改源代码,首先要读懂代码了解代码.国内的一些公司