php根据用户输入单词,匹配相似单词
最近在使用一款app背单词的时候,会在某个单词下面,列出与之相类似的单词。于是我在想这个功能是如何做的,自己使用php版本,做了个简单的例子。
大致思路如下:
1、生成英文单词库,并将单词放置redis里(当然放数据库也可以)
首先我们看第一步,我的做法是,从网上找一个很大的文本,big.txt。这个文本包含了几万个单词,然后利用正则,将里面的单词,拿出来并存到redis库里面。但问题是,我们在使用php读取大文件时,并还要利用正则去匹配单词的话,这个动作是非常消耗内存的,于是我的做法是,一行一行的去读取文本,并把这行里面的单词,在取出来,存到库里。
核心代码如下:
public function word($perLine){
preg_match_all('/[a-z]+/i',$perLine,$matches);
if($matches[0]){
foreach ($matches[0] as $key => $value) {
$word = strtolower($value);
if($this -> redisObj->exists($word)){
$this -> redisObj->incr($word); }else{ $this -> redisObj->set($word, 1);
}
}
}
} /**
* 返回文件从X行到Y行的内容(支持php5、php4)
* @param string $filename 文件名
* @param int $startLine 开始的行数
* @param int $endLine 结束的行数
* @return string
*/
public function getFileLines($filename, $startLine = 1, $endLine=50, $method='rb') {
$content = array();
$count = $endLine - $startLine;
// 判断php版本(因为要用到SplFileObject,PHP>=5.1.0)
if(version_compare(PHP_VERSION, '5.1.0', '>=')){
$fp = new SplFileObject($filename, $method);
$fp->seek($startLine-1);// 转到第N行, seek方法参数从0开始计数
for($i = 0; $i <= $count; ++$i) {
$lineContent=$fp->current();// current()获取当前行内容
$this -> word($lineContent);
$fp->next();// 下一行
}
}
}
这个程序代码,可能要执行比较长的时间,根据个人电脑而定,反正我的电脑执行了差不多有个把小时。好吧,总之这样,我们自己就制作了个词库,虽然并没有包含所有单词,不过至少测试是可以的啦。
2、得到用户单词,生成与之相类似的单词
我们开始处理第二步,我们需要得到用户单词,生成"编辑距离"为1的所有单词。
那么什么是"编辑距离"为1的单词呢?大概有如下几种情况
(1)deletes:依次删除word的每一位后、所形成的所有新词。比如,'abc'对应的deletes就是 ['bc', 'ac', 'ab'] 。
(2)transposes:依次交换word的邻近两位,所形成的所有新词。比如,'abc'对应的transposes就是 ['bac', 'acb'] 。
(3)replaces:将word的每一位依次替换成其他25个字母,所形成的所有新词。比如,'abc'对应的replaces就是 ['abc', 'bbc', 'cbc', ... , 'abx', ' aby', 'abz' ] ,一共包含78个词(26 × 3)。
(4)inserts:在word的邻近两位之间依次插入一个字母,所形成的所有新词。比如,'abc' 对应的inserts就是['aabc', 'babc', 'cabc', ..., 'abcx', 'abcy', 'abcz'],一共包含104个词(26 × 4)。
有了思路后,代码如下:
public function getSimilarWord_1($word){
if(trim($word)){
$word = strtolower($word); for($i=0; $i<strlen($word);$i++){
$deletes[] = substr_replace($word,'',$i,1);
}
for($i=0; $i<strlen($word)-1;$i++){
$transposes[] = substr_replace($word,$word[$i+1],$i,1);
}
for($i=0; $i<strlen($word);$i++){
for($j=0;$j<strlen($this -> alphabet);$j++){
$replaces[] = substr_replace($word,$this -> alphabet[$j],$i,1);
}
}
for($j=0;$j<strlen($this -> alphabet);$j++){
$inserts[] = $this -> alphabet[$j] . $word;
} for($i=0; $i<strlen($word)-1;$i++){
for($j=0;$j<strlen($this -> alphabet);$j++){
$inserts[] = substr($word,0,$i+1) . $this -> alphabet[$j] . substr($word,-(strlen($word)-$i-1));
} } for($j=0;$j<strlen($this -> alphabet);$j++){
$inserts[] = $word . $this -> alphabet[$j];
}
$rs = array_unique(array_merge($deletes, $transposes, $replaces, $inserts));
echo count($rs);
$realWords = $this -> getRealWord($rs);
print_r($realWords);
return $realWords; }
}
好了,上面是一个简单的例子,实际生产环境中,还要考虑"编辑距离"为2的单词,而且上面这个程序是每次都要去库里面查找近似单词的,实际上,我们也可以再建张表,然后把所有单词的对应关系,跑出来,并存到对应关系表里面。这样用户输入一个单词之后,我们就可以直接查找出近似单词了。
当然这个程序再改改的话,也可以做成纠正用户输错单词的程序了。
完整代码:
http://git.oschina.net/kjr/kangjianrong_public/tree/master/similarWord?dir=1&filepath=similarWord&oid=3af896968d7c31003cfdfb06675ce0aa9f46e9c9&sha=f90f85b3c9dda717593e74f05053c5525b2cf710
欢迎转载,请注明出处:
http://www.cnblogs.com/kangjianrong/p/5818738.html
参考:
http://www.ruanyifeng.com/blog/2012/10/spelling_corrector.html
http://www.cnblogs.com/whoamme/p/3522467.html
php根据用户输入单词,匹配相似单词的更多相关文章
- 【原】ComboBoxety用户输入自动匹配
//在界面构造函数里加入下面两行代码 this.cbbDepartureAirport.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode ...
- 第七章 用户输入和while语句
大多数编程都旨在解决最终用户的问题,为此通常需要从用户那里获取一些信息.例如,假设有人要判断自己是否到了投票的年龄,要编写回答这个问题的程序,就需要知道用户的年龄,这样才能给出答案.因此,这种程序需要 ...
- Python手把手教程之用户输入input函数
函数input() 函数 input() 让程序暂停运行,等待用户输入一些文本.获取用户输入后,Python将其存储在一个变量中,以方便你使用. 例如,下面的程序让用户输入一些文本,再将这些文本呈现给 ...
- vim 精确匹配查找单词【转】
删除文件中所有的空行:g/^\s*$/d 去掉所有的行尾空格::%s/\s\+$// 整个文件特定字符串的替换:%s/old_word/new_word/g 删除从当前行开始到最后一行的所有内容:., ...
- python Trie树和双数组TRIE树的实现. 拥有3个功能:插入,删除,给前缀智能找到所有能匹配的单词
#coding=utf- #字典嵌套牛逼,别人写的,这样每一层非常多的东西,搜索就快了,树高26.所以整体搜索一个不关多大的单词表 #还是O(). ''' Python 字典 setdefault() ...
- Java如何在正则表达式中匹配重复单词?
在Java编程中,如何在正则表达式中匹配重复单词? 以下示例显示了如何使用regex.Matcher类的p.matcher()方法和m.group()方法在正则表达式中搜索重复的单词. package ...
- java String中的replace(oldChar,newChar) replace(CharSequence target,CharSequence replacement) replaceAll replaceFirst 面试题:输入英文语句,单词首字符大写后输出 char String int 相互转换
package com.swift; import java.util.Scanner; public class FirstChat_ToCaps_Test { public static void ...
- 正则表达式 整理(\w \s \d 点 贪婪匹配 非贪婪匹配 * + ? {} | [] ^ $ \b 单词边界 分组、re.findall()、re.split()、re.search()、re.match()、re.compile()、re.sub())
re.findall 匹配到正则表达式的字符,匹配到的每个字符存入一个列表,返回一个匹配到的所有字符列表 一. 匹配单个字符 import re # \w 匹配所有字母.数字.下划线 re.find ...
- 三道习题(1、将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别。 #输入格式:按字典序由小到大输入若干个单词,每个单词占一行,以end结束输入。)
#coding=gbk ''' 1.将单词表中由相同字母组成的单词归成一类,每类单词按照单词的首字母排序,并按 #每类中第一个单词字典序由大到小排列输出各个类别. #输入格式:按字典序由小到大输入若干 ...
随机推荐
- 职业定位(移动端、ios开发、Android开发)
移动端 移动端webapp开发必备知识:http://www.chinaz.com/manage/2012/1128/283974.shtml 设计一款好的移动App,有哪些基本规则?http://w ...
- Angular - - angular.bind、angular.bootstrap、angular.copy
angular.bind 返回一个调用self的函数fn(self代表fn里的this).可以给fn提供参数args(*).这个功能也被称为局部操作,以区别功能. 格式:angular.bind(se ...
- Delphi 常用函数记录
//判断是否是数字 function IsNumeric(sDestStr: string): Boolean; //简写多余汉字 function SimplifyWord(sWord: strin ...
- Apache自带压力测试工具ab用法简介
ab命令原理 ab命令会创建很多的并发访问线程,模拟多个访问者同时对某一URL进行访问.它的测试目标是基于URL的,因此,既可以用来测试Apache的负载压力,也可以测试nginx.lighthttp ...
- js模块化开发——AMD规范
这个系列的第一部分介绍了Javascript模块的基本写法,今天介绍如何规范地使用模块. 七.模块的规范 先想一想,为什么模块很重要? 因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就 ...
- xtemplate语法
XTemplate 是富逻辑的 KISSY 模板引擎,面向复杂的业务逻辑场景,同时保持高性能和丰富的配置方法,是易学易懂的模板语言. 一个典型的XTemplate模板实例: Hello {{name} ...
- Bootstrap入门(十五)组件9:面板组件
Bootstrap入门(十五)组件9:面板组件 虽然不总是必须,但是某些时候你可能需要将某些 DOM 内容放到一个盒子里.对于这种情况,可以试试面板组件. 1.基本实例 2.带标题的面板 3.情景效果 ...
- mac下sublime 配置查看源码
sublime及package control的安装查看之前一篇文章:http://www.cnblogs.com/xdwa/p/5805101.html 安装ctags 安装完毕package co ...
- 数据库SQL,NoSQL之小感悟
遇到1000万数据表 最近遇到一个问题,就是单表数据过的存储及查询问题.举个例子:1000万的数据存在一个表中,字段4-5个样子,日常 开发中难免要做过滤.排序.分页.如果把这几个放在一起即要过滤又要 ...
- matlab 利用while循环计算平均值和方差(第二版)
第一版中因为公式中含有:分母项:n(n-1),而程序并没有对输入数进行判定,如果仅仅输入一个或者一个都不输入,将会出现除0的情况 基于此,进行第二版改进. 代码: % 脚本文件:states.m % ...