⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fts3_porter.c

📁 最新的sqlite3.6.2源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*** 2006 September 30**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.***************************************************************************** Implementation of the full-text-search tokenizer that implements** a Porter stemmer.*//*** The code in this file is only compiled if:****     * The FTS3 module is being built as an extension**       (in which case SQLITE_CORE is not defined), or****     * The FTS3 module is being built into the core of**       SQLite (in which case SQLITE_ENABLE_FTS3 is defined).*/#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_FTS3)#include <assert.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include "fts3_tokenizer.h"/*** Class derived from sqlite3_tokenizer*/typedef struct porter_tokenizer {  sqlite3_tokenizer base;      /* Base class */} porter_tokenizer;/*** Class derived from sqlit3_tokenizer_cursor*/typedef struct porter_tokenizer_cursor {  sqlite3_tokenizer_cursor base;  const char *zInput;          /* input we are tokenizing */  int nInput;                  /* size of the input */  int iOffset;                 /* current position in zInput */  int iToken;                  /* index of next token to be returned */  char *zToken;                /* storage for current token */  int nAllocated;              /* space allocated to zToken buffer */} porter_tokenizer_cursor;/* Forward declaration */static const sqlite3_tokenizer_module porterTokenizerModule;/*** Create a new tokenizer instance.*/static int porterCreate(  int argc, const char * const *argv,  sqlite3_tokenizer **ppTokenizer){  porter_tokenizer *t;  t = (porter_tokenizer *) sqlite3_malloc(sizeof(*t));  if( t==NULL ) return SQLITE_NOMEM;  memset(t, 0, sizeof(*t));  *ppTokenizer = &t->base;  return SQLITE_OK;}/*** Destroy a tokenizer*/static int porterDestroy(sqlite3_tokenizer *pTokenizer){  sqlite3_free(pTokenizer);  return SQLITE_OK;}/*** Prepare to begin tokenizing a particular string.  The input** string to be tokenized is zInput[0..nInput-1].  A cursor** used to incrementally tokenize this string is returned in ** *ppCursor.*/static int porterOpen(  sqlite3_tokenizer *pTokenizer,         /* The tokenizer */  const char *zInput, int nInput,        /* String to be tokenized */  sqlite3_tokenizer_cursor **ppCursor    /* OUT: Tokenization cursor */){  porter_tokenizer_cursor *c;  c = (porter_tokenizer_cursor *) sqlite3_malloc(sizeof(*c));  if( c==NULL ) return SQLITE_NOMEM;  c->zInput = zInput;  if( zInput==0 ){    c->nInput = 0;  }else if( nInput<0 ){    c->nInput = (int)strlen(zInput);  }else{    c->nInput = nInput;  }  c->iOffset = 0;                 /* start tokenizing at the beginning */  c->iToken = 0;  c->zToken = NULL;               /* no space allocated, yet. */  c->nAllocated = 0;  *ppCursor = &c->base;  return SQLITE_OK;}/*** Close a tokenization cursor previously opened by a call to** porterOpen() above.*/static int porterClose(sqlite3_tokenizer_cursor *pCursor){  porter_tokenizer_cursor *c = (porter_tokenizer_cursor *) pCursor;  sqlite3_free(c->zToken);  sqlite3_free(c);  return SQLITE_OK;}/*** Vowel or consonant*/static const char cType[] = {   0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0,   1, 1, 1, 2, 1};/*** isConsonant() and isVowel() determine if their first character in** the string they point to is a consonant or a vowel, according** to Porter ruls.  **** A consonate is any letter other than 'a', 'e', 'i', 'o', or 'u'.** 'Y' is a consonant unless it follows another consonant,** in which case it is a vowel.**** In these routine, the letters are in reverse order.  So the 'y' rule** is that 'y' is a consonant unless it is followed by another** consonent.*/static int isVowel(const char*);static int isConsonant(const char *z){  int j;  char x = *z;  if( x==0 ) return 0;  assert( x>='a' && x<='z' );  j = cType[x-'a'];  if( j<2 ) return j;  return z[1]==0 || isVowel(z + 1);}static int isVowel(const char *z){  int j;  char x = *z;  if( x==0 ) return 0;  assert( x>='a' && x<='z' );  j = cType[x-'a'];  if( j<2 ) return 1-j;  return isConsonant(z + 1);}/*** Let any sequence of one or more vowels be represented by V and let** C be sequence of one or more consonants.  Then every word can be** represented as:****           [C] (VC){m} [V]**** In prose:  A word is an optional consonant followed by zero or** vowel-consonant pairs followed by an optional vowel.  "m" is the** number of vowel consonant pairs.  This routine computes the value** of m for the first i bytes of a word.**** Return true if the m-value for z is 1 or more.  In other words,** return true if z contains at least one vowel that is followed** by a consonant.**** In this routine z[] is in reverse order.  So we are really looking** for an instance of of a consonant followed by a vowel.*/static int m_gt_0(const char *z){  while( isVowel(z) ){ z++; }  if( *z==0 ) return 0;  while( isConsonant(z) ){ z++; }  return *z!=0;}/* Like mgt0 above except we are looking for a value of m which is** exactly 1*/static int m_eq_1(const char *z){  while( isVowel(z) ){ z++; }  if( *z==0 ) return 0;  while( isConsonant(z) ){ z++; }  if( *z==0 ) return 0;  while( isVowel(z) ){ z++; }  if( *z==0 ) return 1;  while( isConsonant(z) ){ z++; }  return *z==0;}/* Like mgt0 above except we are looking for a value of m>1 instead** or m>0*/static int m_gt_1(const char *z){  while( isVowel(z) ){ z++; }  if( *z==0 ) return 0;  while( isConsonant(z) ){ z++; }  if( *z==0 ) return 0;  while( isVowel(z) ){ z++; }  if( *z==0 ) return 0;  while( isConsonant(z) ){ z++; }  return *z!=0;}/*** Return TRUE if there is a vowel anywhere within z[0..n-1]*/static int hasVowel(const char *z){  while( isConsonant(z) ){ z++; }  return *z!=0;}/*** Return TRUE if the word ends in a double consonant.**** The text is reversed here. So we are really looking at** the first two characters of z[].*/static int doubleConsonant(const char *z){  return isConsonant(z) && z[0]==z[1] && isConsonant(z+1);}/*** Return TRUE if the word ends with three letters which** are consonant-vowel-consonent and where the final consonant** is not 'w', 'x', or 'y'.**** The word is reversed here.  So we are really checking the** first three letters and the first one cannot be in [wxy].*/static int star_oh(const char *z){  return    z[0]!=0 && isConsonant(z) &&    z[0]!='w' && z[0]!='x' && z[0]!='y' &&    z[1]!=0 && isVowel(z+1) &&    z[2]!=0 && isConsonant(z+2);}/*** If the word ends with zFrom and xCond() is true for the stem** of the word that preceeds the zFrom ending, then change the ** ending to zTo.**** The input word *pz and zFrom are both in reverse order.  zTo** is in normal order. **** Return TRUE if zFrom matches.  Return FALSE if zFrom does not** match.  Not that TRUE is returned even if xCond() fails and** no substitution occurs.*/static int stem(  char **pz,             /* The word being stemmed (Reversed) */  const char *zFrom,     /* If the ending matches this... (Reversed) */  const char *zTo,       /* ... change the ending to this (not reversed) */  int (*xCond)(const char*)   /* Condition that must be true */){  char *z = *pz;  while( *zFrom && *zFrom==*z ){ z++; zFrom++; }  if( *zFrom!=0 ) return 0;  if( xCond && !xCond(z) ) return 1;  while( *zTo ){    *(--z) = *(zTo++);  }  *pz = z;  return 1;}/*** This is the fallback stemmer used when the porter stemmer is** inappropriate.  The input word is copied into the output with** US-ASCII case folding.  If the input word is too long (more** than 20 bytes if it contains no digits or more than 6 bytes if** it contains digits) then word is truncated to 20 or 6 bytes** by taking 10 or 3 bytes from the beginning and end.*/static void copy_stemmer(const char *zIn, int nIn, char *zOut, int *pnOut){  int i, mx, j;  int hasDigit = 0;  for(i=0; i<nIn; i++){    int c = zIn[i];    if( c>='A' && c<='Z' ){      zOut[i] = c - 'A' + 'a';    }else{      if( c>='0' && c<='9' ) hasDigit = 1;      zOut[i] = c;    }  }  mx = hasDigit ? 3 : 10;  if( nIn>mx*2 ){    for(j=mx, i=nIn-mx; i<nIn; i++, j++){      zOut[j] = zOut[i];    }    i = j;  }  zOut[i] = 0;  *pnOut = i;}/*** Stem the input word zIn[0..nIn-1].  Store the output in zOut.** zOut is at least big enough to hold nIn bytes.  Write the actual** size of the output word (exclusive of the '\0' terminator) into *pnOut.**** Any upper-case characters in the US-ASCII character set ([A-Z])

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -