英文分词相比中文分词要简单得多,可以根据空格和标点符号来分词,然后对每一个单词进行词干还原和词形还原,去掉停用词和非英文内容。词干还原算法最经典的就是波特算法(Porter Algorithm官网http://tartarus.org/~martin/PorterStemmer/ )

Java版的波特词干提取算法代码如下:

import java.io.*;/**
* 实现波特词干提取算法,将一个单词转换为它的原型。
*/
class PorterStemmer{private char[] b; /* 用来存待词干提取的单词(以char的形式) */private int i,     /* b中的元素位置(偏移量) */i_end, /* 要抽取词干单词的结束位置 */j, k;private static final int INC = 50;/* 随着b的大小增加数组要增长的长度(防止溢出) */public PorterStemmer(){b = new char[INC];i = 0;i_end = 0;}/*** 增加一个字符到要存放待处理的单词的数组。添加完字符时, * 可以调用stem(void)方法来进行抽取词干的工作。* @param ch 字符*/public void add(char ch){  if (i == b.length){char[] new_b = new char[i+INC];for (int c = 0; c < i; c++) new_b[c] = b[c];b = new_b;}b[i++] = ch;}/*** 增加字符数组ch到存放待处理的单词的数组b* @param ch 字符数组*/public void add(char[] ch){add(ch,ch.length);}/*** 增加wLen长度的字符数组到存放待处理的单词的数组b。* @param w 字符数组* @param wLen 数组长度*/public void add(char[] w, int wLen){if (i+wLen >= b.length){  char[] new_b = new char[i+wLen+INC];for (int c = 0; c < i; c++) new_b[c] = b[c];b = new_b;}for (int c = 0; c < wLen; c++) b[i++] = w[c];}/*** 返回单词的词干。*/public String toString() { return new String(b,0,i_end); }/*** 返回单词的词干的长度*/public int getResultLength() { return i_end; }/*** 返回单词的词干char[]*/public char[] getResultBuffer() { return b; }/*** cons(i):参数i:int型;返回值bool型。当i为辅音时,返回真;否则为假* @param i b数组下标* @return cons(i) 为真 <=> b[i] 是一个辅音 */private final boolean cons(int i){  switch (b[i]){  case 'a': case 'e': case 'i': case 'o': case 'u': return false;//y开头,为辅;否则看i-1位,如果i-1位为辅,y为元,反之亦然。 case 'y': return (i==0) ? true : !cons(i-1);default: return true;}}/** *//*** m():返回值:int型。表示单词b介于0和j之间辅音序列的个数。* 现假设c代表辅音序列,而v代表元音序列。<..>表示任意存在。于是有如下定义:<c><v>          结果为 0<c>vc<v>       结果为 1<c>vcvc<v>    结果为 2<c>vcvcvc<v> 结果为 3....* @return 单词b介于0和j之间辅音序列的个数*/private final int m(){  int n = 0;//辅音序列的个数,初始化int i = 0;//偏移量//<c>while(true){  if (i > j) return n;//如果超出最大偏移量,直接返回nif (!cons(i)) break; //如果是元音,中断i++;  //辅音移一位,直到元音的位置 }i++;//移完辅音,从元音的第一个字符开始 while(true){  //循环计算vc的个数 //<v>while(true){  //循环判断v  if (i > j) return n;if (cons(i)) break; //出现辅音则终止循环i++;}i++;n++;//<c>while(true){  //循环判断c if (i > j) return n;if (!cons(i)) break;i++;}i++;}}/*** vowelinstem():返回值:bool型。表示单词b介于0到i之间是否存在元音。* @return vowelinstem() 为真 <=> 0,...j 包含一个元音*/private final boolean vowelinstem(){  int i; for (i = 0; i <= j; i++) if (!cons(i)) return true;return false;}/*** doublec(j):参数j:int型;返回值bool型。* 这个函数用来表示在j和j-1位置上的两个字符是否是相同的辅音。* @param j 数组b的下标* @return doublec(j) 为真 <=> j,(j-1) 包含两个一样的辅音*/private final boolean doublec(int j){  if (j < 1) return false;if (b[j] != b[j-1]) return false;return cons(j);}/*** cvc(i):参数i:int型;返回值bool型。* 对于i,i-1,i-2位置上的字符,它们是“辅音-元音-辅音”的形式,* 并且对于第二个辅音,它不能为w、x、y中的一个。* 这个函数用来处理以e结尾的短单词。比如说cav(e),lov(e),hop(e),crim(e)。* 但是像snow,box,tray就不符合条件。* @param i 下标* @return boolean*/private final boolean cvc(int i){  if (i < 2 || !cons(i) || cons(i-1) || !cons(i-2)) return false;else{int ch = b[i];if (ch == 'w' || ch == 'x' || ch == 'y') return false;}return true;}/*** ends(s):参数:String;返回值:bool型。用于判断b是否以s结尾。* @param s 字符串* @return 判断b是否以s结尾*/private final boolean ends(String s){  int l = s.length();int o = k-l+1;if (o < 0) return false;for (int i = 0; i < l; i++) if (b[o+i] != s.charAt(i)) return false;j = k-l;return true;}/*** 把b在(j+1)...k位置上的字符设为s,同时,调整k的大小* @param s 字符串*/private final void setto(String s){  int l = s.length();int o = j+1;for (int i = 0; i < l; i++) b[o+i] = s.charAt(i);k = j+l;}/*** 在m()>0的情况下,调用setto(s)。* @param s 字符串*/private final void r(String s) { if (m() > 0) setto(s); }//分六步来进行处理的过程/** step1() 处理复数,以及ed和ing结束的单词。比如:caresses  ->  caressponies    ->  ponities      ->  ticaress    ->  caresscats      ->  catfeed      ->  feedagreed    ->  agreedisabled  ->  disablematting   ->  matmating    ->  matemeeting   ->  meetmilling   ->  millmessing   ->  messmeetings  ->  meet*/private final void step1(){  if (b[k] == 's'){  if (ends("sses")) k -= 2; //以“sses结尾” else if (ends("ies")) setto("i"); //以ies结尾,置为ielse if (b[k-1] != 's') k--;//两个s结尾不处理 }if (ends("eed")) { //以“eed”结尾,当m>0时,左移一位if (m() > 0) k--; } else if ((ends("ed") || ends("ing")) && vowelinstem()){  k = j;if (ends("at")) setto("ate"); else if (ends("bl")) setto("ble"); else if (ends("iz")) setto("ize"); else if (doublec(k)){  //如果有两个相同辅音  k--;int ch = b[k];if (ch == 'l' || ch == 's' || ch == 'z') k++;}else if (m() == 1 && cvc(k)) setto("e");}}/** step2() 如果单词中包含元音,并且以y结尾,将y改为i */private final void step2() { if (ends("y") && vowelinstem()){b[k] = 'i'; }}/** step3() 将双后缀的单词映射为单后缀。 * 所以 -ization ( = -ize 加上 -ation) 被映射到 -ize 等等。 * 注意在去除后缀之前必须确保m()>0.*/private final void step3() { if (k == 0) return;  switch (b[k-1]){case 'a': if (ends("ational")) { r("ate"); break; }if (ends("tional")) { r("tion"); break; }break;case 'c': if (ends("enci")) { r("ence"); break; }if (ends("anci")) { r("ance"); break; }break;case 'e': if (ends("izer")) { r("ize"); break; }break;case 'l': if (ends("bli")) { r("ble"); break; }if (ends("alli")) { r("al"); break; }if (ends("entli")) { r("ent"); break; }if (ends("eli")) { r("e"); break; }if (ends("ousli")) { r("ous"); break; }break;case 'o': if (ends("ization")) { r("ize"); break; }if (ends("ation")) { r("ate"); break; }if (ends("ator")) { r("ate"); break; }break;case 's': if (ends("alism")) { r("al"); break; }if (ends("iveness")) { r("ive"); break; }if (ends("fulness")) { r("ful"); break; }if (ends("ousness")) { r("ous"); break; }break;case 't': if (ends("aliti")) { r("al"); break; }if (ends("iviti")) { r("ive"); break; }if (ends("biliti")) { r("ble"); break; }break;case 'g': if (ends("logi")) { r("log"); break; }}}/** step4() 处理-ic-,-full,-ness等等后缀。和步骤3有着类似的处理 */private final void step4() { switch (b[k]){case 'e': if (ends("icate")) { r("ic"); break; }if (ends("ative")) { r(""); break; }if (ends("alize")) { r("al"); break; }break;case 'i': if (ends("iciti")) { r("ic"); break; }break;case 'l': if (ends("ical")) { r("ic"); break; }if (ends("ful")) { r(""); break; }break;case 's': if (ends("ness")) { r(""); break; }break;} }/** step5() 在<c>vcvc<v>情形下,去除-ant,-ence等后缀。 */private final void step5(){   if (k == 0) return; /* for Bug 1 */switch (b[k-1]){  case 'a': if (ends("al")) break; return;case 'c': if (ends("ance")) break;if (ends("ence")) break; return;case 'e': if (ends("er")) break; return;case 'i': if (ends("ic")) break; return;case 'l': if (ends("able")) break;if (ends("ible")) break; return;case 'n': if (ends("ant")) break;if (ends("ement")) break;if (ends("ment")) break;/* element etc. not stripped before the m */if (ends("ent")) break; return;case 'o': if (ends("ion") && j >= 0 && (b[j] == 's' || b[j] == 't')) break;/* j >= 0 fixes Bug 2 */if (ends("ou")) break; return;/* takes care of -ous */case 's': if (ends("ism")) break; return;case 't': if (ends("ate")) break;if (ends("iti")) break; return;case 'u': if (ends("ous")) break; return;case 'v': if (ends("ive")) break; return;case 'z': if (ends("ize")) break; return;default: return;}if (m() > 1) k = j;}/** step6() 在m()>1的情况下,移除末尾的“e”。*/private final void step6(){  j = k;if (b[k] == 'e'){  int a = m();if (a > 1 || a == 1 && !cvc(k-1)) k--;}if (b[k] == 'l' && doublec(k) && m() > 1) k--;}/** 通过调用add()方法来将单词放入词干器数组b中 * 可以通过下面的方法得到结果: getResultLength()+getResultBuffer() or toString(). */public void stem(){  k = i - 1;if (k > 1) { step1(); step2(); step3(); step4(); step5(); step6(); }i_end = k+1; i = 0;}/*** Test program for demonstrating the Stemmer.  It reads text from a* a list of files, stems each word, and writes the result to standard* output. Note that the word stemmed is expected to be in lower case:* forcing lower case must be done outside the Stemmer class.* Usage: Stemmer file-name file-name ...* @param args file-name file-name ...*/public static void main(String[] args){char[] w = new char[501];PorterStemmer s = new PorterStemmer();for (int i = 0; i < args.length; i++)try{FileInputStream in = new FileInputStream(args[i]);try{ while(true){  int ch = in.read();if (Character.isLetter((char) ch)){int j = 0;while(true){  ch = Character.toLowerCase((char) ch);w[j] = (char) ch;if (j < 500) j++;ch = in.read();if (!Character.isLetter((char) ch)){//to test add(char ch)for (int c = 0; c < j; c++) s.add(w[c]);//or, to test add(char[] w, int j) // s.add(w, j); s.stem();String u;//and now, to test toString() : u = s.toString();//to test getResultBuffer(), getResultLength() ://u = new String(s.getResultBuffer(), 0, s.getResultLength()); System.out.print(u);break;}}}if (ch < 0) break;System.out.print((char)ch);}}catch (IOException e){  System.out.println("error reading " + args[i]);break;}}catch (FileNotFoundException e){  System.out.println("file " + args[i] + " not found");break;}}/*** 对某个单词进行词干提取,返回词干* @param s 单词字符串* @return 词干*/public String stem(String s){char[] ch=s.toLowerCase().toCharArray();add(ch);stem();return toString();}    /**对一系列文本中的所有单词stemming* @param stemFile 待stemming的文本文件路径组成的字符串数组*//*** * @param stemFile* @throws IOException */public static void porterMain(String[] stemFile) throws IOException{char[] w = new char[501];PorterStemmer s = new PorterStemmer(); for (int i = 0; i < stemFile.length; i++)try{FileInputStream in = new FileInputStream(stemFile[i]);FileWriter targetFileWriter = new FileWriter(stemFile[i] + "stemed");try{ while(true){  int ch = in.read();if (Character.isLetter((char) ch)){int j = 0;while(true){  ch = Character.toLowerCase((char) ch);w[j] = (char) ch;if (j < 500) j++;ch = in.read();if (!Character.isLetter((char) ch)){/* to test add(char ch) */for (int c = 0; c < j; c++) s.add(w[c]);/* or, to test add(char[] w, int j) *//* s.add(w, j); */s.stem();String u;/* and now, to test toString() : */u = s.toString();/* to test getResultBuffer(), getResultLength() : *//* u = new String(s.getResultBuffer(), 0, s.getResultLength()); *///System.out.print(u);targetFileWriter.write(u + "\n");break;}}}if (ch < 0) break;System.out.print((char)ch);}targetFileWriter.close();}catch (IOException e){  System.out.println("error reading " + stemFile[i]);break;}}catch (FileNotFoundException e){  System.out.println("file " + stemFile[i] + " not found");break;}}
}

参考自:http://blog.csdn.net/noobzc1/article/details/8902881

(1)英文分词——波特词干提取算法相关推荐

  1. Porter Algorithm ---------词干提取算法

    在英语中,一个单词常常是另一个单词的"变种",如:happy=>happiness,这里happy叫做happiness的词干(stem).在信息检索系统中,我们常常做的一件 ...

  2. NLP:自然语言处理技术之词语级别相关术语解释(如上位词/WordNet)、基于词汇层面的词法分析六大任务(分词/词性标注/词干提取-词形还原/新词发现/形态分析/拼写校正)的简介及其应用

    NLP:自然语言处理技术之词语级别相关术语解释(如上位词/WordNet).基于词汇层面的词法分析(Lexical Analysis)六大任务(分词/词性标注/词干提取-词形还原/新词发现/形态分析/ ...

  3. NLTK(3)处理文本、分词、词干提取与词形还原

    文章目录 访问文本 @字符串处理 @编码 @正则表达式 分词 @正则表达式分词(不好) Tokenize命令 @自定义函数 规范化文本 将文本转换为小写 查找词干 @自定义函数(不好) NLTK词干提 ...

  4. [搜索]波特词干(Porter Streamming)提取算法详解(1)

    英语词汇由两部分构成,词干和词缀,词缀又分前缀和后缀,这里的词干提取仅只去除后缀的操作. 波特词干提取算法的原文在这里 http://tartarus.org/~martin/PorterStemme ...

  5. 波特词干算法 - 残阳似血的博客

    波特词干算法 - 残阳似血的博客 波特词干算法 - 残阳似血的博客 波特词干算法 位于分类 自然语言处理 在英语中,一个单词常常是另一个单词的"变种",如:happy=>ha ...

  6. 词形变换和词干提取工具(英文)

    转载自: http://www.cnblogs.com/kaituorensheng/p/3437807.html 词形变换和词干提取工具(英文) 在信息检索和文本挖掘中,需要对一个词的不同形态进行归 ...

  7. java lucene词干提取_词形变换和词干提取工具(英文)

    在信息检索和文本挖掘中,需要对一个词的不同形态进行归并,即词形规范化,从而提高文本处理的效率.例如:词根run有不同的形式running.ran另外runner也和run有关.这里涉及到两个概念: 词 ...

  8. c语言英文分词,英文分词的算法和原理

    英文分词的算法和原理 根据文档相关性计算公式 分词质量对于基于词频的相关性计算是无比重要的 英文(西方语言)语言的基本单位就是单词,所以分词特别容易做,只需要3步: 根据空格/符号/段落 分隔,得到单 ...

  9. [搜索]波特词干(Porter Streamming)提取算法详解(3)

     接上 [搜索]波特词干(Porter Streamming)提取算法详解(2) 下面分为5大步骤来使用前面提到的替换条件来进行词干提取. 左边是规则,右边是提取成功或者失败的例子(用小写字母表示 ...

最新文章

  1. python学习笔记011——内置函数__module__、__name__
  2. 新手入门深度学习 | 2-4:时间序列数据建模流程示例
  3. webpack基础第一篇(配置文件)
  4. miniui 查询_JQueryMiniUI按照时间进行查询的实现方法
  5. python爬取天天基金网_天天基金网精选基金组合年度报告20201231
  6. 电商设计师套用PSD分层模板,玩转详情页的!
  7. iPhone 13或有8款配色;vivo百万年薪招工程师;特斯拉新增行车记录视频紧急情况自动保存功能|极客头条...
  8. 20200725每日一句
  9. 正确使用计算机键盘的方法是,电脑键盘指法练习及图示
  10. web制作、开发人员需知的Web缓存知识
  11. 2022年全球市场雷达目标模拟器总体规模、主要生产商、主要地区、产品和应用细分研究报告
  12. IntelliJ IDEA现有项目连接SVN(2)
  13. LabVIEW编程开发Agilent 34401A(Keysight 34401A)例程与相关资料
  14. 无线AP和无线路由器区别 wifi热点
  15. 倍福PLC部署Jenkins入门使用笔记
  16. 计算机cpu的速度越来越快 这导致,计算机一级笔试模拟题(1-6)
  17. 【电商】电商供应链产品介绍
  18. 增强学习(Q-learning)
  19. STM8L学习笔记-GPIO端口操作(一)
  20. e5运行Linux系统,CPU-Z 1.96更新介绍,可用Wine及deepin-wine5在Linux中运行

热门文章

  1. 为什么越来越多的网站域名不加www前缀?
  2. Android打包混淆压缩
  3. 【密码学】——初识JAVA加密体系(JCA)
  4. 基于协同过滤的算法 图书推荐系统
  5. 你真的理解函数式编程吗?
  6. linux卸载informatica,Informatica在linux下安装搭建
  7. Android 统计流量数据
  8. system/bt目录内容解析
  9. 包装类,正则表示式,Arrays类
  10. 北大计算机硕士选调有发展吗,985毕业生不愿当公务员?别被忽悠了,看看北大毕业生的去向!...