今天被问到Java字符串搜索,中午抽空研究了String的源码。
int indexOf(String str)
核心查找代码:
for (int i = sourceOffset + fromIndex; i <= max; i++) { /* Look for first character. */ if (source[i] != first) { while (++i <= max && source[i] != first); } /* Found first character, now look at the rest of v2 */ if (i <= max) { int j = i + 1; int end = j + targetCount - 1; for (int k = targetOffset + 1; j < end && source[j] == target[k]; j++, k++); if (j == end) { /* Found whole string. */ return i - sourceOffset; } } }
这段代码的简单思想是:从源字符串的索引0开始,按字符查找,直到最大索引max(max=源字符串长度 - 子字符串长度),找到和子串第一个字符(first)匹配的字符,记下索引位置并且存放到变量i中;
接下去判断i是否超出max,如果超出,则直接返回-1,查找结束;
如果i小于max,则源字符串索引i加1,子字符串索引k也加1,然后比对这两个索引对应的字符:
如果相等,两个字符串的索引再各自加1继续循环;
如果不相等,跳出循环;
继续执行下面的代码: 如果j==end意味着子串遍历完了(也就是在源字符串查找到了子串),返回查找到的子串索引,程序结束;
如果不满足j==end,则源字符串的索引i++,然后重新执行上面过程,直到源字符串遍历到最大索引max(这中间可能找到子串,提前返回);
这种字符串查找的算法谈不上高效,但是对于小字符串来说应该够用了;
对于字符串查找场景较多,并且字符串很长的情况(可能需要查找的子串靠近源字符串的后半部分),这个方法可能效率不够高;
接着写 int lastIndexOf(String str),先上源码:
int strLastIndex = targetOffset + targetCount - 1; char strLastChar = target[strLastIndex]; int min = sourceOffset + targetCount - 1; int i = min + fromIndex; startSearchForLastChar: while (true) { while (i >= min && source[i] != strLastChar) { i--; } if (i < min) { return -1; } int j = i - 1; int start = j - (targetCount - 1); int k = strLastIndex - 1; while (j > start) { if (source[j--] != target[k--]) { i--; continue startSearchForLastChar; } } return start - sourceOffset + 1; }
查找的原理大致和indexOf相同,只不过lastIndexOf是从尾部开始查找的,并且中间的一些细节还是和indexOf不同的。
上面这段代码的主要意思是:
初始计算部分:
计算子串的最后一个字符,存入变量strLastChar中;
计算源字符串查找的终点索引,存入变量min;
计算源字符串的查找起点索引,存入变量i;
进入第一个while循环:
while (i >= min && source[i] != strLastChar) { i--; }
这段代码是在源字符串找到和子串最后一个字符相等的字符,把他的索引存入变量i(从尾部开始查找)
如果索引i小余min,意味着已经不在上面规定的查找范围之内了,直接返回-1;
如果索引i合法,那么确定源字符串的查找范围(起点j=i-1,终点start=起点-子串长度+1)【源码中终点的变量是start,作者觉得这是查找的终点,请注意区分】
确定子串的查找起点k=子串最后一个字符索引-1
用源字符串的索引j处的字符和子串索引k处的字符比较,并且j和k各自减1:
如果字符相等,则继续执行上面的比较,直到索引j递减到j>start(索引j超出了查找的终点start),则跳出循环继续往下执行;
如果字符不相等,则程序跳转到锚点startSearchForLastChar处,按照上面的逻辑继续执行;
如果if (source[j--] != target[k--])的比对一直相等,并且把while (j > start)循环执行完了,意味着在源字符串找到了子串(只需要找到第一个就可以了,当然是从末尾开始找的),程序返回子串的索引。
对于很长的字符串查找的优化,推荐一篇文章: KMP子字符串查找算法分析与实现
全文完。
相关推荐
动态规划算法:从1到26分别对应a-z的每一个字母,输入一串数字的字符串,转换为字母,输出所有可能的字母序列。如123->abc、lc、aw 本资源是按照二叉树的思想解决该问题。从字符串的头部开始,每次可以取一个或者两...
第十三章 字符串13.1 不可变的String13.2 重载“+”与StringBuilder13.2.1 javap反编译13.3 无意识的递归13.4 String常用方法13.5格式化输出13.5.1 printf()13.5.2 System,out.format()13.5.3 Formatter类13.5.4 ...
JAVA的确是一种令程序员陷入两难境地的言语, 确切的说是思想. 它提供了如此丰富的library,让程序员能够很容易的写出功能强大的程序. 同时它也封装了如此多的细节, 让程序员能够轻易的写出很拙略的程序. 它所代表的...
全书共12章,主要包括:Java 2编程基础、面向对象编程原理、接口、包、字符串类String和StringBuffer、异常处理、输入和输出、多线程、Java小程序、GUI布局管理、对象序列化、内隐类、Adapter类和事件处理等,非常...
5.1.2 String创建字符串常量 5.1.3 StringBuffer创建字符串 5.2 连接字符串 5.2.1 与字符串的连接 5.2.2 与其他数据类型的连接 5.3 String字符串操作 5.3.1 基本操作 5.3.2 比较 5.3.3 转化 5.3.4 查找 ...
1、Java语言基础:包括环境搭建、基本数据类型、包装类、变量、常量定义、控制结构、String字符串处理等; 2、Java语言面向对象:面向对象思想、类声明与对象实例化、成员变量、方法重载,封装性以及子类继承与多态...
返回最长字符串 X,要求满足 X 能除尽 str1 且 X 能除尽 str2.如果ST有公共因子,反向连接等于正向连接求最大公约数public String g
1. 熟悉Java中的String、StringBuffer、Math、包装器类的使用方法。 2. 使用常用类解决一般性的应用问题。 3. 掌握JavaSE API文档的使用方法。 二、实验内容 1. 编写一个程序,输出一个字符串中的大写英文字母数,...
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。 至于为什么要把String类设计成不可...
字符串(java.lang.String类)的使用 90 字符串相等的判断 92 思考作业 93 上机作业 94 第四章 异常机制 95 导引问题 95 异常(Exception)的概念 96 异常分类 96 Error 97 Error和Exception的区别 97 Exception 97 ...
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。至于为什么要把String类设计成不可变类,...
非常详细的javaSE知识点梳理,涵盖字符串:(String,StringBuffer,StringBuilder)、数组、面向对象思想、可视化(swing)、异常、集合框架、IO、线程、网络协议、xml等,内附有代码讲解
9.1.3 字符串对象修改228 9.1.4 类型转换230 9.2 StringBuffer类的使用231 9.3 StringBuilder类的使用233 9.4 日期类简介234 9.5 Java语言国际化时间获取与计算238 9.6 Random类和Math类240 9.7 本章习题243 第10章 ...
传递字符串数组 参数传递 JNI调用 代码清单15-10 在Linux平台上调用C函数的例程——Sample3 public class Sample3 { public native String[] stringMethod(String text); public static void main(String[] ...
//连接字符串 private Connection conn=null; //数据库连接对象 public Statement sm=null; //数据库语句对象 public void ConnectDB(){ try { Class.forName( driverName); conn = DriverManager.get...
Tomjson,一个"短小精悍"的 json 解析库,tomjson使用Java语言编写,主要作用是把Java对象(JavaBean)序列化为json格式字符串,将json格式字符串序列化为相对应的Java对象(JavaBean)。项目地址:...
能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 能够使用Date, Calendar, Locale, DateFormat,NumberFormat类创建、改变和显示日期、数字和货币...
2、掌握 Java 基本语法,重点是面向对象的思想和语法。 3、掌握控制台下(应用程序)的输入输出方法,作为后续部分实验的基础。 二、实验类型 设计型。 三、实验内容 1、打开实验室计算机上的集成开发环境 Eclipse ...
System.out.printf() 可插入带 % 的输入类型,前两种只可以插入转义符, 不能插入 % 的数据或字符串 在 printf 里面,输出有5个部分 %[argument_index$][flags][width][.precision]conversion 以“%”开头,[第几个...
如果出现一大串的字符系列,则表示环境变量设置成功。 JAVA实验报告一全文共10页,当前为第4页。 JAVA实验报告一全文共10页,当前为第4页。 配置成功截图: 图1.1 显示java的版本信息图 简单的程序设计: 题目1:在...