1、 爲何Alice不支持中文
由於Alice的question都會被bitoflife.chatterbean.text.Transformations類中的fit函數過濾,而過濾的表達式就是:html
private finalPattern fitting = Pattern.compile("[^A-Z0-9]+");算法
只會保留英文字符和數字字符。順帶說一句,由於Alice會將question所有轉爲大寫,因此上面的表達式中沒有a-z區間。app
爲了讓中文不被過濾掉,就將上面的過濾式中添加中文字符。函數
privatefinal Pattern fitting = Pattern.compile("[^A-Z0-9\u4e00-\u9FA5]+")ui
2、 Alice支持中文的原理
先解釋一下,Alice對英文支持的原理:spa
簡而言之:在語料庫中,找出匹配的用戶question的pattern,再返回pattern對應的template內容做爲answer。.net
詳細點就是:Alice初始化時,將AIML文件中的<pattern>標籤的內容根據空格切分,組成一個Graphmaster對象;用戶的question也根據空格切分,根據匹配算法在Graphmaster對象中找到匹配的pattern標籤,再返回該pattern對應的template內容。orm
Graphmaster參考:http://www.alicebot.org/documentation/matching.htmlhtm
Alice支持英文中的關鍵一點就是:英文輸入有空格,而中文輸入沒有空格,Alice就不會切分中文字符,只會把整個中文語句當作英文中一個單詞。對象
因此支持中文的關鍵一點就是:爲中文語句加空格。
立刻想到了中文分詞器,我用的是IK分詞器.接下來問題就轉化爲:怎麼爲中文語句加空格?在什麼地方加空格?
有兩個地方要處理:
² 讀取AIML文件中的pattern標籤時,須要加空格。
² 讀取用戶question時,要加空格。
3、 代碼實踐
IK分詞器封裝函數
這是就很少說了,csdn博客多得是IK分詞器用法。
public static StringIKAnalysis(String str) {
if(str.getBytes().length == str.length()) {
//若是不包含中文,就直接返回。
return str;
}else {
//因爲IK分詞器,不支持特殊字符,因此將 * 改成中文字符「這是星號」,中文分詞之後再將「這是星號」修正爲爲 *
//同理將 _改成中文字符串「這是下劃線」,中文分詞之後再將「這是下劃線」修正爲 _
str= str.replaceAll("\\*","這是星號").replaceAll("_","這是下劃線");
}
StringBuffersb =new StringBuffer();
try {
byte[] bt =str.getBytes();
InputStreamip =new ByteArrayInputStream(bt);
Readerread =new InputStreamReader(ip);
//設置爲智能分詞
IKSegmenteriks =new IKSegmenter(read,true);
Lexemet;
while ((t =iks.next()) !=null) {
//在每一個分詞元以後添加空格
sb.append(t.getLexemeText()+" ");
}
//sb.delete(sb.length() - 1, sb.length());
}catch (IOException e) {
//TODOAuto-generated catch block
}
returnsb.toString().replaceAll("這是星號","*").replaceAll("這是下劃線","_");
}
讀取AIML文件的pattern標籤時加空格
AIML的讀取解析工做由bitoflife.chatterbean.aiml.AIMLHandler類完成的。
修改pushTextNode函數,根據參數來判斷是否調用中文分詞器。
/**
*將一個節點的文本信息壓入棧中,並根據參數決定是否調用中文分詞器。
*@param isToSegment 標識是否調用中文分詞器
*/
privatevoidpushTextNode(Boolean isToSegment) {
Stringpushed =text.toString();
text.delete(0,text.length());
if (ignoreWhitespace)
pushed= pushed.replaceAll("^[\\s\n]+|[\\s\n]{2,}|\n","");
if (!"".equals(pushed.trim())){
if(!isToSegment) {
stack.push(newText(pushed));
}else {
pushed= pushed.toUpperCase();
stack.push(newText(cn.edu.scut.cs.IKAnalyzer.ChineseSegmenter.IKAnalysis(pushed)));
}
}
}
在startElement和endElement函數中爲pattern和that標籤內的中文字符添加空格。將pushTextNode()函數的調用語句改成:
pushTextNode(qname.toLowerCase().equals("pattern")
||qname.toLowerCase().equals("that"));
順帶說一句that標籤也可能須要中文分詞的。
讀取用戶question時加空格 這個很簡單,在public void normalization(Sentencesentence)函數中第二行添加調用中文分詞函數: