`
nudtgk2000
  • 浏览: 72800 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Porter Stemmer 波特词干算法

阅读更多
    /*  
      
       Porter stemmer in Java. The original paper is in  
      
           Porter, 1980, An algorithm for suffix stripping, Program, Vol. 14,  
           no. 3, pp 130-137,  
      
       See also http://www.tartarus.org/~martin/PorterStemmer  
      
       History:  
      
       Release 1  
      
       Bug 1 (reported by Gonzalo Parra 16/10/99) fixed as marked below.  
       The words 'aed', 'eed', 'oed' leave k at 'a' for step 3, and b[k-1]  
       is then out outside the bounds of b.  
      
       Release 2  
      
       Similarly,  
      
       Bug 2 (reported by Steve Dyrdahl 22/2/00) fixed as marked below.  
       'ion' by itself leaves j = -1 in the test for 'ion' in step 5, and  
       b[j] is then outside the bounds of b.  
      
       Release 3  
      
       Considerably revised 4/9/00 in the light of many helpful suggestions  
       from Brian Goetz of Quiotix Corporation (brian@quiotix.com).  
      
       Release 4  
      
    */   
       
    import java.io.*;   
       
    /**  
      * Stemmer, implementing the Porter Stemming Algorithm  
      *  
      * The Stemmer class transforms a word into its root form.  The input  
      * word can be provided a character at time (by calling add()), or at once  
      * by calling one of the various stem(something) methods.  
      */   
       
    class Stemmer   
    {  private char[] b;   
       private int i,     /* offset into b */   
                   i_end, /* offset to end of stemmed word */   
                   j, k;   
       private static final int INC = 50;   
                         /* unit of size whereby b is increased */   
       public Stemmer()   
       {  b = new char[INC];   
          i = 0;   
          i_end = 0;   
       }   
       
       /**  
        * Add a character to the word being stemmed.  When you are finished  
        * adding characters, you can call stem(void) to stem the word.  
        */   
       
       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;   
       }   
       
       
       /** Adds wLen characters to the word being stemmed contained in a portion  
        * of a char[] array. This is like repeated calls of add(char ch), but  
        * faster.  
        */   
       
       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];   
       }   
       
       /**  
        * After a word has been stemmed, it can be retrieved by toString(),  
        * or a reference to the internal buffer can be retrieved by getResultBuffer  
        * and getResultLength (which is generally more efficient.)  
        */   
       public String toString() { return new String(b,0,i_end); }   
       
       /**  
        * Returns the length of the word resulting from the stemming process.  
        */   
       public int getResultLength() { return i_end; }   
       
       /**  
        * Returns a reference to a character buffer containing the results of  
        * the stemming process.  You also need to consult getResultLength()  
        * to determine the length of the result.  
        */   
       public char[] getResultBuffer() { return b; }   
       
       /* cons(i) is true => b[i] is a consonant. */   
       
       private final boolean cons(int i)   
       {  switch (b[i])   
          {  case 'a': case 'e': case 'i': case 'o': case 'u': return false;   
             case 'y': return (i==0) ? true : !cons(i-1);   
             default: return true;   
          }   
       }   
       
       /* m() measures the number of consonant sequences between 0 and j. if c is  
          a consonant sequence and v a vowel sequence, and <..> indicates arbitrary  
          presence,  
      
             <c><v>       gives 0  
             <c>vc<v>     gives 1  
             <c>vcvc<v>   gives 2  
             <c>vcvcvc<v> gives 3  
             ....  
       */   
       
       private final int m()   
       {  int n = 0;   
          int i = 0;   
          while(true)   
          {  if (i > j) return n;   
             if (! cons(i)) break; i++;   
          }   
          i++;   
          while(true)   
          {  while(true)   
             {  if (i > j) return n;   
                   if (cons(i)) break;   
                   i++;   
             }   
             i++;   
             n++;   
             while(true)   
             {  if (i > j) return n;   
                if (! cons(i)) break;   
                i++;   
             }   
             i++;   
           }   
       }   
       
       /* vowelinstem() is true => 0,...j contains a vowel */   
       
       private final boolean vowelinstem()   
       {  int i; for (i = 0; i = j; i++) if (! cons(i)) return true;   
          return false;   
       }   
       
       /* doublec(j) is true => j,(j-1) contain a double consonant. */   
       
       private final boolean doublec(int j)   
       {  if (j  1) return false;   
          if (b[j] != b[j-1]) return false;   
          return cons(j);   
       }   
       
       /* cvc(i) is true => i-2,i-1,i has the form consonant - vowel - consonant  
          and also if the second c is not w,x or y. this is used when trying to  
          restore an e at the end of a short word. e.g.  
      
             cav(e), lov(e), hop(e), crim(e), but  
             snow, box, tray.  
      
       */   
       
       private final boolean cvc(int i)   
       {  if (i  2 || !cons(i) || cons(i-1) || !cons(i-2)) return false;   
          {  int ch = b[i];   
             if (ch == 'w' || ch == 'x' || ch == 'y') return false;   
          }   
          return true;   
       }   
       
       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;   
       }   
       
       /* setto(s) sets (j+1),...k to the characters in the string s, readjusting  
          k. */   
       
       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;   
       }   
       
       /* r(s) is used further down. */   
       
       private final void r(String s) { if (m() > 0) setto(s); }   
       
       /* step1() gets rid of plurals and -ed or -ing. e.g.  
      
              caresses  ->  caress  
              ponies    ->  poni  
              ties      ->  ti  
              caress    ->  caress  
              cats      ->  cat  
      
              feed      ->  feed  
              agreed    ->  agree  
              disabled  ->  disable  
      
              matting   ->  mat  
              mating    ->  mate  
              meeting   ->  meet  
              milling   ->  mill  
              messing   ->  mess  
      
              meetings  ->  meet  
      
       */   
       
       private final void step1()   
       {  if (b[k] == 's')   
          {  if (ends("sses")) k -= 2; else   
             if (ends("ies")) setto("i"); else   
             if (b[k-1] != 's') k--;   
          }   
          if (ends("eed")) { 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() turns terminal y to i when there is another vowel in the stem. */   
       
       private final void step2() { if (ends("y") && vowelinstem()) b[k] = 'i'; }   
       
       /* step3() maps double suffices to single ones. so -ization ( = -ize plus  
          -ation) maps to -ize etc. note that the string before the suffix must give  
          m() > 0. */   
       
       private final void step3() { if (k == 0) return; /* For Bug 1 */ 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() deals with -ic-, -full, -ness etc. similar strategy to step3. */   
       
       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() takes off -ant, -ence etc., in context <c>vcvc<v>. */   
       
       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() removes a final -e if m() > 1. */   
       
       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--;   
       }   
       
       /** Stem the word placed into the Stemmer buffer through calls to add().  
        * Returns true if the stemming process resulted in a word different  
        * from the input.  You can retrieve the result with  
        * 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;   
       }   
          
       /* Stem the inFileName into outFileName */   
          
       public void stem(String inFileName,String outFileName)   
       {   
          char[] w=new char[501];   
          Stemmer s = new Stemmer();   
     //     for (int i = 0; i  args.length; i++)   
          try   
          {   
             FileInputStream in = new FileInputStream(inFileName);   
             FileOutputStream out = new FileOutputStream(outFileName);   
                
             try   
             { while(true)   
       
               {  int ch = in.read();   
                      
                  if (ch > 0xa0)    
                   {   
                       out.write(ch);   
                       continue;   
                       
                   }   
                     
                  else 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) || ch > 0xa0)  // Read to the end of one word   
                        {   
                           /* 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()); */   
                              int len=u.length();   
                              for (int k=0;k<len;k++)   
                              out.write((char)(u.charAt(k)));   
       
                     //         out.write(u);   
                           }   
                           break;   
                        }   
                     }   
                  }   
                     
                  if (ch  0) break;   
                  out.write((char)ch);   
               }   
             }   
             catch (IOException e)   
             {  System.out.println("error reading " + inFileName + "or write "+ outFileName + "error!");   
                        }   
          }   
          catch (FileNotFoundException e)   
          {  System.out.println("file " + inFileName + " not found" + "or" + "file" +outFileName + "open error");   
          }   
            
       }   
       public static void main(String []argv)   
       {   
        //String spath="e:\\lengzi\\software\\weka-3-5-0\\reut2-000stopwordsremoval.sgm";   
        //String dpath="e:\\lengzi\\software\\weka-3-5-0\\reut2-000stemmer.sgm";   
       //   Stemmer s = new Stemmer();   
        //s.stem(spath,dpath);   
        String spath;   
        String dpath,dpath1;   
        String sfile = "E:\\TRAIN2";   
        String dfile = "e:\\TRAIN3";   
        File sfolder = new File(sfile);   
        File[ ] entries = sfolder.listFiles( );   
        Stemmer s = new Stemmer();   
        for(int i=0; i<entries.length; i++) {   
            spath = entries[i].getPath();   
            dpath1 =dfile+"\\"+entries[i].getName();   
            File subfolder = new File(spath);   
            File[] subentries = subfolder.listFiles();   
            for(int j=0; j<subentries.length;j++)   
            {   
                spath = subentries[j].getPath();   
                dpath = dpath1+"\\"+subentries[j].getName();   
                try{   
                FileWriter fw = new FileWriter(dpath);   
                fw.close();   
                }catch (IOException e)   
                 {  System.out.println("error!");   
                 }   
                s.stem(spath,dpath);   
            }   
               
            }   
       }   
       
    }   

 一篇学习笔记:波特词干算法——残阳似血的博客 , 有对算法的详细讲解和资源链接

 一个使用了Porter Stemmer 的例子:分词程序集成了一个可以提取词干的开源项目成果 , 借鉴用法

分享到:
评论

相关推荐

    Stemmer波特词干算法

    应用最为广泛的、中等复杂程度的、基于后缀剥离的词干提取算法是波特词干算法,也叫波特词干器(Porter Stemmer)。详见官方网站。比较热门的检索系统包括Lucene、Whoosh等中的词干过滤器就是采用的波特词干算法。

    波特词干算法c语言实现

    波特词干算法由Martin Porter于1980年提出,并发表在《Program》杂志上。该算法的主要目的是通过一系列规则来识别并删除英语单词的后缀,从而得到单词的基本形式或词干。这种方法虽然简单,但在当时已经是非常有效的...

    porter stemmer vc 工程

    Porter Stemmer是一种著名的英文词干提取算法,由Martin Porter在1980年提出,主要用于处理英文文本,减少词汇的形态变化,将词汇还原到它们的基本形式,以便于文本分析、信息检索和自然语言处理等领域。在VC...

    wink-porter2-stemmer:Martin F Porter博士的Porter Stemmer算法V2的Java语言实现

    wink-porter2-stemmer Martin F Porter博士实现 的屈折字划分成使用其碱形式wink-porter2-stemmer 。 安装 使用进行安装: npm install wink-porter2-stemmer --save ...使用Porter2词干算法阻止变

    retext-porter-stemmer:重写Porter Stemmer的实现

    retext-porter-stemmer 实现。 安装 : npm install retext-porter-stemmer retext-porter-stemmer也可用于 , 和 ,以及作为AMD,CommonJS和globals模块的和模块。 用法 var retext = require ( 'retext' ) ; ...

    在Rust 中实现 Porter 词干算法_rust_代码_下载

    Porter词干算法是一种在自然语言处理中广泛使用的文本预处理技术,它的主要目标是将词汇还原到其基本形式,通常称为词干。这个过程被称为词干化,它有助于减少词汇多样性,使得文本分析和信息检索更为高效。Rust 是...

    german-stemmer:PHP的一个简短的Porter Stemmer算法实现类

    德国施特默使用 Porter 词干分析器算法将一个词简化为德语词干。 参考: - http://snowball.tartarus.org/algorithms/porter/stemmer.html- http://snowball.tartarus.org/algorithms/german/stemmer.html用法:$...

    基于C版本算法的快速 Porter 词干分析器

    Fast-stemmer 只是对多线程的简单封装 波特词干算法 这个 gem 添加了一个 String#stem 方法,它与 stemmer gem 冲突。 它比后者快一个数量级(并且使用更少的内存)。

    Stemming-Latin:Porter拉丁词干算法的实现

    Porter拉丁词干算法是自然语言处理(NLP)领域中广泛应用的一个词干提取算法,由Martin Porter在1973年提出。它主要用于英语文本,但经过一些调整,也可以应用于其他拉丁语系的语言,如西班牙语、法语、意大利语等。...

    stem词干提取

    在英文中,常见的词干提取算法有Porter Stemmer和Lancaster Stemmer。Porter Stemmer是由Martin Porter开发的,它通过一套规则化的步骤来去掉单词的后缀,如“-ing”、“-ed”、“-s”等,但不保证得到的词干是词汇...

    rct-stemming:Porter的词干算法的Javascript实现

    #Martin Porter阻止算法 有关完整详细信息,请参见。 在特定条件下,辅音是AEIOU和Y以外的字母或单词。 元音是非辅音字母。 使用的符号 c =辅音 v =元音 m =度量 C = 0或更多辅音 V = 0或更多的元音 m = 0表示空...

    mysql-porter-stemmer:MySQL 中的波特语音

    MySQL Porter Stemmer 是一个用于MySQL数据库的文本处理工具,它实现了Porter stemming算法,该算法主要用于英文词汇的词干提取。在信息检索、文本分析和自然语言处理领域,词干提取是一个关键步骤,通过减少词汇到...

    前端开源库-en-stemmer

    **前端开源库-en-stemmer** 是一个专为前端开发者设计的开源库,它主要实现了英语词干提取(Stemming)算法,特别是波特(Porter)词干提取算法。词干提取是自然语言处理(NLP)领域的一个重要技术,它的目标是将...

    ooPorter:用ooRexx编码的Porter词干或词干分析器算法-开源

    这是从Ansi-C到Martin Porter 1980发布的阻止例程的ooRexx的ooRexx逐行端口。Porter的原始源代码已被注释掉并由相应的(oo)Rexx代码尽可能地模拟。 这不是良好或快速(oo)Rexx编程的示例,它仅是Porter阻止例程...

    搬运工的声音-Golang开发

    Go的Porter Stemmer这是Martin Porter的Porter词干算法的C实现的相当简单的端口。 该端口基于的C版本可从以下位置下载:http://tartarus.org/~martin/Port Go的Porter Stemmer这是Martin Porter的Porter干算法的C...

    porter-stemmer

    "porter-stemmer"是一个广泛使用的英文词干提取算法,主要应用于自然语言处理(NLP)领域。在Python中,porter-stemmer算法通常通过特定的库如nltk(Natural Language Toolkit)或Snowball Stemmer来实现。词干提取...

    开源项目-caneroj1-stemmer.zip

    在Go语言中实现Porter-Stemmer算法,开发者通常会创建一个Stemmer接口,定义一个`Stem`方法来接收一个英文单词并返回其词干。此外,可能会包含一些辅助函数,用于执行上述的各个步骤,如处理元音变化、前缀和后缀等...

    porter stemming 分词算法

    porter stemming算法是一种广泛应用于英文文本处理中的词干提取方法,由Martin Porter在1973年提出。它的主要目的是减少单词的不同形式,将它们还原到基本的形式,通常被称为词根或词干。这种方法有助于在信息检索、...

    Porter算法1

    Porter算法,全称为Porter Stemming Algorithm,是马丁·波特(Martin Porter)在1979年开发的一种英文词干提取算法。它主要用于去除英语单词中的常见形态和屈折变化,以便在信息检索系统中进行术语标准化。Porter...

    stemr:Snowball English(porter2)stemmer算法的Javascript(TypeScript)实现

    · stemr软件包提供了 English(porter2)stemmer算法的javascript(TypeScript)实现。例子 import { stem } from "stemr" ;stem ( "stemming" ) ;// =&gt; "stem

Global site tag (gtag.js) - Google Analytics