?? code3.txt
字號:
分詞程序集成了一個可以提取詞干的開源項目成果
這兩天正好在項目中需要提取詞干(word stemming),詞干是什么?比如documentation這個詞,它的詞干就是document。再比如tables這個復數形式,它的詞干就是tabl。詞干也許可以理解為類似于詞根一樣的概念。我沒有去查準確的定義,不過我想它的用處是顯而易見的。我們如果想比較兩個詞的相似程度,比如下面兩個詞:go和went。這怎么辦,其實從目的上講我們是希望這兩個詞有較高的相似度的(語義上極為相似),然而從簡單的字符串處理方法上,比如編輯距離的處理方式,這兩個詞也許就很不相似了。然而經過提取詞干以后,一切就不一樣了,went能夠被還原成go,很有用的方法。再比如典型的應用:stem和stemming這兩個詞如果要考慮語義相似性,那應當是非常相似的(只不過是兩種時態而已),可是從編輯距離或者VSM的角度考慮,也許他們的相似性要大打折扣。然而stemming提取詞干以后,就還原成了stem。
我想過自己去實現一個這樣的工具,然而翻閱了一些經典的英語語法書籍,發現要考慮的事情太多了,感興趣的可以去這個地方看看:http://www.phon.ucl.ac.uk/home/dick/enc/intro.htm 于是我尋找各種現有的開源項目。其實首先接觸到的是一個叫做KIMMO的工具,我也是無意中通過它才知道了提取詞干這回事。它是用腳本語言編寫的,我對這個方面不很熟悉,不敢貿然使用。然后才知道提取詞干方面也許是一個很權威的方法:Porter Stemming算法,它的主頁是:http://www.tartarus.org/~martin/PorterStemmer/ 幸運的,我找到了它的一個開源的應用,是他們自己的工作結晶,一個叫做Snowball的項目,地址是:http://snowball.tartarus.org/ 他們的庫可以在這兒下載:http://snowball.tartarus.org/dist/libstemmer_java.tgz
集成這個工具來提取詞干是很方便的,要注意的是這個工具不僅支持提取英文詞干,也支持法語、俄語等多種其他語言(當然不包括中文)。下面是一個典型的應用實例,我將它集成到了我的分詞程序中,以下是全部源代碼。其中,為了適合我們應用的需要,將數字部分保留了,浮點數也可以被提取和保留下來,然而因為時間緊迫的關系暫時用了兩邊掃描。
import java.util.*;
import java.lang.reflect.Method;
import org.tartarus.snowball.*;
public class SplitWords {
/* 分隔符的集合 */
private final String delimiters = " \t\n\r\f~!@#$%^&*()_+|`-=\\{}[]:\";'<>?,./'1234567890";
/* 語言 */
private final String language = "english";
public String[] split(String source) {
/* 提取數字 */
Vector vectorForNumber = new Vector();
flag3: for (int i = 0; i < source.length(); i++) {
char thisChar = source.charAt(i);
StringBuffer thisNumber = new StringBuffer();
boolean hasDigit = false;
if (Character.isDigit(thisChar)) {
thisNumber.append(thisChar);
for (++i; i < source.length(); i++) {
thisChar = source.charAt(i);
if ((thisChar == '.') && !hasDigit) {
thisNumber.append(thisChar);
hasDigit = true;
} else if (Character.isDigit(thisChar)) {
thisNumber.append(thisChar);
} else {
if (thisNumber.length() != 0) {
vectorForNumber.addElement(thisNumber.toString());
continue flag3;
}
}
}
if (thisNumber.length() != 0) {
vectorForNumber.addElement(thisNumber.toString());
}
}
}
/* 剔除. */
int positionOfDot;
StringBuffer tempSource = new StringBuffer(source);
while ((positionOfDot = tempSource.indexOf(".")) != -1) {
tempSource.deleteCharAt(positionOfDot);
}
source = tempSource.toString();
/* 根據分隔符分詞 */
StringTokenizer stringTokenizer = new StringTokenizer(source,
delimiters);
/* 所有的詞 */
Vector vector = new Vector();
/* 全大寫的詞 -- 不用提詞干所以單獨處理 */
Vector vectorForAllUpperCase = new Vector();
/* 根據大寫字母分詞 */
flag0: while (stringTokenizer.hasMoreTokens()) {
String token = stringTokenizer.nextToken();
/* 全大寫的詞單獨處理 */
boolean allUpperCase = true;
for (int i = 0; i < token.length(); i++) {
if (!Character.isUpperCase(token.charAt(i))) {
allUpperCase = false;
}
}
if (allUpperCase) {
vectorForAllUpperCase.addElement(token);
continue flag0;
}
/* 非全大寫的詞 */
int index = 0;
flag1: while (index < token.length()) {
flag2: while (true) {
index++;
if ((index == token.length())
|| !Character.isLowerCase(token.charAt(index))) {
break flag2;
}
}
vector.addElement(token.substring(0, index).toLowerCase());
token = token.substring(index);
index = 0;
continue flag1;
}
}
/* 提詞干 */
try {
Class stemClass = Class.forName("org.tartarus.snowball.ext."
+ language + "Stemmer");
SnowballProgram stemmer = (SnowballProgram) stemClass.newInstance();
Method stemMethod = stemClass.getMethod("stem", new Class[0]);
Object[] emptyArgs = new Object[0];
for (int i = 0; i < vector.size(); i++) {
stemmer.setCurrent((String) vector.elementAt(i));
stemMethod.invoke(stemmer, emptyArgs);
vector.setElementAt(stemmer.getCurrent(), i);
}
} catch (Exception e) {
e.printStackTrace();
}
/* 合并 */
for (int i = 0; i < vectorForAllUpperCase.size(); i++) {
vector.addElement(vectorForAllUpperCase.elementAt(i));
}
for (int i = 0; i < vectorForNumber.size(); i++) {
vector.addElement(vectorForNumber.elementAt(i));
}
/* 轉為數組形式 */
String[] array = new String[vector.size()];
Enumeration enumeration = vector.elements();
int index = 0;
while (enumeration.hasMoreElements()) {
array[index] = (String) enumeration.nextElement();
index++;
}
/* 打印顯示 */
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
/* 返回 */
return array;
}
public static void main(String args[]) {
SplitWords sw = new SplitWords();
sw
.split("These 232 tables are for ARE-Company using only. The I.S.B.N number of J.Smith's book is ISBN302.1.2.");
//sw.split("123");
}
}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=429056
public class SplitWords {
/* 分隔符的集合*/
private String delimiters = " \t\n\r\f~!@#$%^&*()_+|`-=\\{}[]:\";'<>?,./'1234567890";
/* 語言*/
private String language = "english";
public String[] split(String source) {
/* 提取數字*/
Vector vectorForNumber = new Vector();
flag3: for (int i = 0; i < source.length(); i++)
{
char thisChar = source.charAt(i);
StringBuffer thisNumber = new StringBuffer();
boolean hasDigit = false;
if (Character.isDigit(thisChar))
{
thisNumber.append(thisChar);
for (++i; i < source.length(); i++)
{
thisChar = source.charAt(i);
if ((thisChar == '.') && !hasDigit)
{
thisNumber.append(thisChar);
hasDigit = true;
}
else
if (Character.isDigit(thisChar))
{
thisNumber.append(thisChar);
}
else
{
if (thisNumber.length() != 0)
{
vectorForNumber.addElement(thisNumber.toString());
continue flag3;
}
}
}
if (thisNumber.length() != 0)
{
vectorForNumber.addElement(thisNumber.toString());
}
}
}
/* 剔除. */
int positionOfDot;
StringBuffer tempSource = new StringBuffer(source);
while ((positionOfDot = tempSource.indexOf(".")) != -1) {
tempSource.deleteCharAt(positionOfDot);
}
source = tempSource.toString();
/* 根據分隔符分詞*/
StringTokenizer stringTokenizer = new StringTokenizer(source,
delimiters);
/* 所有的詞*/
Vector vector = new Vector();
/* 全大寫的詞-- 不用提詞干所以單獨處理*/
Vector vectorForAllUpperCase = new Vector();
/* 根據大寫字母分詞*/
flag0: while (stringTokenizer.hasMoreTokens())
{
String token = stringTokenizer.nextToken();
/* 全大寫的詞單獨處理*/
boolean allUpperCase = true;
for (int i = 0; i < token.length(); i++) {
if (!Character.isUpperCase(token.charAt(i))) {
allUpperCase = false;
}
}
if (allUpperCase) {
vectorForAllUpperCase.addElement(token);
continue flag0;
}
/* 非全大寫的詞*/
int index = 0;
flag1: while (index < token.length())
{
flag2: while (true)
{
index++;
if ((index == token.length()) || !Character.isLowerCase(token.charAt(index)))
{
break flag2;
}
}
vector.addElement(token.substring(0, index).toLowerCase());
token = token.substring(index);
index = 0;
continue flag1;
}
}
/* 提詞干*/
try {
Class stemClass = Class.forName("org.tartarus.snowball.ext."
+ language + "Stemmer");
SnowballProgram stemmer = (SnowballProgram) stemClass.newInstance();
Method stemMethod = stemClass.getMethod("stem", new Class[0]);
Object[] emptyArgs = new Object[0];
for (int i = 0; i < vector.size(); i++) {
stemmer.setCurrent((String) vector.elementAt(i));
stemMethod.invoke(stemmer, emptyArgs);
vector.setElementAt(stemmer.getCurrent(), i);
}
} catch (Exception e) {
e.printStackTrace();
}
/* 合并*/
for (int i = 0; i < vectorForAllUpperCase.size(); i++) {
vector.addElement(vectorForAllUpperCase.elementAt(i));
}
for (int i = 0; i < vectorForNumber.size(); i++) {
vector.addElement(vectorForNumber.elementAt(i));
}
/* 轉為數組形式*/
String[] array = new String[vector.size()];
Enumeration enumeration = vector.elements();
int index = 0;
while (enumeration.hasMoreElements()) {
array[index] = (String) enumeration.nextElement();
index++;
}
/* 打印顯示*/
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
/* 返回*/
return array;
}
public static void main(String args[]) {
SplitWords sw = new SplitWords();
sw.split("These 232 tables are for ARE-Company using only. The I.S.B.N number of J.Smith's book is ISBN302.1.2.");
//sw.split("123");
}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -