Java实现简易的分词器功能
业务需求:
生活中常见的搜索功能大概可分为以下几类:
- 单关键词。如“Notebook”
- 双关键词加空格。如“Super Notebook”
- 多关键词加多空格。如“Intel Super Notebook”
当然,还有四甚至五关键词,这些搜索场景在生活中可以用罕见来形容,不在我们的讨论范围。我们今天就以上三种生活中最常见的搜索形式进行探讨分析。业务需求也很简单,假设我们要完成一个搜索功能,业务层、持久层、控制层不在我们讨论的范围,仅讨论分词功能如何实现。
分析:
假设用户键入的搜索内容为以下内容:
Intel Super Notebook
我们可以利用Java中String强大而丰富的方法来慢慢拼凑一个小算法来达到目的。String中大多数方法的参数和返回值都与下标相关,那么,分析上述语句的下标,我们可发现如下内容:
上述内容红色是我们分词的关键内容。对于一个语句而言(不是语言学上通俗的语句,因为该句没有主谓宾),重要的就是各单词或词组的首字母下标与该单词或词组后面最近一个空格。我们发现,Intel
这个单词首字母下标为0,距离该单词后面最近的一个空格下标为5;Super
首字母下标为距离该单词前面最近的一个空格的下标加1,也就是6;Notebook
首字母下标为距离该单词前面最近的一个空格的下标加1,也就是12;最后就是该语句的尾下标,也就是19。
当然,实际情况会有用户多输入了两个甚至三个空格在某两个单词之间,例如如下形式:
Intel Super Notebook
(注意这里的空格为每个单词之间为2个)
这个问题很容易解决,我们把两个或三个空格替换为一个空格即可(为什么不是四个或者更多?因为现实情况是用户不太可能在各个单词之间连按多个空格),如下:
sentence = sentence.replace(" ", " "); sentence = sentence.replace(" ", " ");
这样以来语句中就只存在单个空格了。
经过分析我们得知,若想对一个语句进行分词,就必须知道各个单词的起始下标才行。起始下标可以由空格的下标得知,那我们该如何得知空格的下标?
很简单,我们写个方法,通过迭代语句的每个单词,判断其是否存在空格即可。方法如下:
private int firstPosition(){ int first = 0; for(int i = 0; i < sentence.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ first = i; return first; } } return first; }
这个方法的作用是判断一个语句中第一个空格的位置。既然有第一个了,肯定要有第二个了。要注意第一个内容是从0开始进行迭代,而第二个空格的判断方法要从第一个空格的位置加1开始,否则迭代的刚好还是第一个空格的位置。内容如下:
private int secondPosition(){ int second = 0; for(int i = (firstPosition() + 1); i < sentence.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ second = i; return second; } } return second; }
第三个为什么不迭代?因为第三个单词之后就没有空格了,就到结尾了。
找出每个空格的下标索引后,我们还需知道语句中含有多少个空格,是没有,还是1个或2个(连续的重复空格在上文已经被替换为单个空格了)。方法如下:
private int countBlank(String s){ // Store single blank signal. int amount = 0; // If s contains single blank signal, and it will increse amount's value of 1 every loop times. for(int i = 0; i < s.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ amount++; } } return amount; }
拿到了空格的总个数及每个空格的下标,我们就可以写个方法进行分割了。由于我是采用了泛型集合作为数据源,这里的方法返回类型就为void。
我们先假设输入的仅有以下内容:
Intel
输入的仅有一个词组。我们先判断其空格的个数,发现为0,那么也不用进行什么操作了,直接添加其作为集合的数据。
public void divide(){ // Record every single blank signal's position. int position1 = firstPosition(); int position2 = secondPosition(); if(sentence.contains(" ")){ } else{ words.add(sentence); } }
现在情况变为输入的内容如下:
Intel Super
我们知道了这个语句共有一个空格,下标为5,长度为11,那可以这样判断:是否包含空格,如果是,那就判断其空格数是否大于等于0,如果为真,就添加到数据源。接着判断其空格数是否大于等于1,如果真,进入下一层判断其空格数是否大于等于1其小于2,如果真,就添加到数据源。内容如下:
public void divide(){ // Record every single blank signal's position. int position1 = firstPosition(); int position2 = secondPosition(); if(sentence.contains(" ")){ int blankAmount = countBlank(sentence); if (blankAmount >= 0) { words.add(sentence.substring(0, position1)); if (blankAmount >= 1) { if(blankAmount >= 1 && blankAmount < 2))); words.add(sentence.substring(position1, sentence.length())); } else { } } } } else{ words.add(sentence); } }
下面就是较为全面的情况了:
Intel Super Notebook
我们判断完两个情况就看第三个情况。第三个单词其获取是通过第二个空格下标与语句长度得来。但第二个单词就要改为第一个空格下标加1与第二个空格下标加1了。那么至此分割方法也就完成了:
public String divide(){ // Record every single blank signal's position. int position1 = firstPosition(); int position2 = secondPosition(); if(sentence.contains(" ")){ int blankAmount = countBlank(sentence); if (blankAmount >= 0) { words.add(sentence.substring(0, position1)); if (blankAmount >= 1) { if(blankAmount >= 1 && blankAmount < 2){ words.add(sentence.substring(position1, sentence.length())); } else { words.add(sentence.substring(position1, position2)); if (blankAmount >= 2) { words.add(sentence.substring(position2, sentence.length())); } } } } } else{ words.add(sentence); } }
测试:
Intel Super Notebook
SIZE:3
POSITION(0): Intel
POSITION(1): Super
POSITION(2): Notebook
Intel Super Notebook
(注这里有重复且连续的空格)
SIZE:3
POSITION(0): Intel
POSITION(1): Super
POSITION(2): Notebook
英特尔 超级 笔记本
SIZE:3
POSITION(0): 英特尔
POSITION(1): 超级
POSITION(2): 笔记本
华为
SIZE:1
POSITION(0): 华为
完整代码:
class DivideWord{ private String sentence; private List<String> words = new ArrayList<String>(); public DivideWord(String sentence) { // Replace two or three blank signal that connected into single blank signal. sentence = sentence.replace(" ", " "); sentence = sentence.replace(" ", " "); this.sentence = sentence; } private int countBlank(String s){ // Store single blank signal. int amount = 0; // If s contains single blank signal, and it will increse amount's value of 1 every loop times. for(int i = 0; i < s.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ amount++; } } return amount; } private int firstPosition(){ int first = 0; for(int i = 0; i < sentence.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ first = i; return first; } } return first; } private int secondPosition(){ int second = 0; for(int i = (firstPosition() + 1); i < sentence.length(); i++){ if(String.valueOf(sentence.charAt(i)).equals(" ")){ second = i; return second; } } return second; } public String divide(){ // Record every single blank signal's position. int position1 = firstPosition(); int position2 = secondPosition(); if(sentence.contains(" ")){ int blankAmount = countBlank(sentence); if (blankAmount >= 0) { words.add(sentence.substring(0, position1)); if (blankAmount >= 1) { if(blankAmount >= 1 && blankAmount < 2){ words.add(sentence.substring(position1, sentence.length())); } else { words.add(sentence.substring(position1, position2)); if (blankAmount >= 2) { words.add(sentence.substring(position2, sentence.length())); } } } } } else{ words.add(sentence); } } public int getSize(){ return words.size(); } public String getWord(int position){ return words.get(position); } } public class DateGet { public static void main(String[] args){ DivideWord divideWord = new DivideWord("英特尔"); divideWord.divide(); System.out.println("SIZE:" + divideWord.getSize()); System.out.println("POSITION :" + divideWord.getWord(0)); } }
到此这篇关于Java实现简易的分词器功能的文章就介绍到这了,更多相关Java分词器功能内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!
相关文章
- 这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
java 运行报错has been compiled by a more recent version of the Java Runtime
java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01- 这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
- 这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
- 说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
- 这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
- 这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
- 这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
- 这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
java 画pdf用itext调整表格宽度、自定义各个列宽的方法
这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31- 这篇文章主要介绍了java正则表达式判断前端参数修改表中另一个字段的值,需要的朋友可以参考下...2021-05-07
Java使用ScriptEngine动态执行代码(附Java几种动态执行代码比较)
这篇文章主要介绍了Java使用ScriptEngine动态执行代码,并且分享Java几种动态执行代码比较,需要的朋友可以参考下...2021-04-15- 这篇文章主要介绍了Java开发实现人机猜拳游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-03
- 这篇文章主要介绍了Java List集合返回值去掉中括号('[ ]')的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-29
Java中lombok的@Builder注解的解析与简单使用详解
这篇文章主要介绍了Java中lombok的@Builder注解的解析与简单使用,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-06- 下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
Java 8 Stream 的终极技巧——Collectors 功能与操作方法详解
这篇文章主要介绍了Java 8 Stream Collectors 功能与操作方法,结合实例形式详细分析了Java 8 Stream Collectors 功能、操作方法及相关注意事项,需要的朋友可以参考下...2020-05-20- 这篇文章主要介绍了Java线程池中的各个参数如何合理设置操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-19
- 在Java中,我们可以利用多线程来最大化地压榨CPU多核计算的能力,下面这篇文章主要给大家介绍了关于java中多线程与线程池基本使用的相关资料,需要的朋友可以参考下...2021-09-13