什么是Search Suggest(搜索建议),上一个截图大家就知道:
对,就是一个输入提示,问了很多人,都以为我是说前台ajax的实现问题。因为很多人都觉得后台数据只要一个select就可以得到……但真的是一个select就可以得到吗?我想了好久都没想到这条select怎么写,于是开始自己琢磨。
我所想到的首先要做的是将输入的东西拆分。比如sg要拆分为[s,g],sog要拆分为[so,g],soug=>[sou,g],sougou => [sou,gou]等等……,当然了,有一些拼音很难拆,比如xian这样的,我的做法是对于这种拼音在拆分环节不进行拆分,即:xian => [xian]。
首先要找到一份字库,我在网上下了一份:
字库对提示的影响很大,好的字库能提高很大效率。载入字库很简单,就是Properties的load,我要说的是载入字库后要进行的一些操作:
载入字库后首先要对字库所有的拼音进行分析,将其分析成一棵树:
如
a
-i
--n
---g
-o
-n
这样才能对用户输入的拼音进行分析。
这是我的代码:
for (Iterator it = ziku.keySet().iterator(); it.hasNext();) { String key = (String) it.next(); char ch = key.charAt(0); PinyinCharNode root = roots.get(ch); if (root == null) { root = PinyinCharNode.valueOf(ch); roots.put(ch, root); } PinyinCharNode node = root; for (int i = 1; i < key.length(); i++) { ch = key.charAt(i); PinyinCharNode tempNode = node.getNodeByChar(ch); if (tempNode == null) { node = node.addNode(ch); } else { node = tempNode; } } }
注释:roots是一个Map类型的对象,保存所有的根节点
下一步工作就是分析用户输入的过程。
1、优先对隔音符进行切分
2、逐个字符进行分析,在第一个字符时获取roots里的数据,如果获取不到,则该这个音符不是声母或a,o,e开头的韵母(a,o,e开头的韵母可以作为单独音节)
3、如果获得root,再分析下一个字符是否为root的子节点。循环下去,直到某个节点,那个节点的下一个字符在这个节点的子节点内无法找到,这时下一个节点作为下一个音节的开始字符
4、循环,直到完成整个字符串
public static List<String> splitPinyin(String pinyin) { String[] pinyins = pinyin.split("'");// 优先使用隔音符 List<String> resultPinyins = new ArrayList<String>(); for (String s : pinyins) { int index = 0; PinyinCharNode node = roots.get(s.charAt(index)); StringBuffer notPinyin = new StringBuffer(); while (index < s.length() && node == null) { notPinyin.append(s.charAt(index)); index++; if (index < s.length()) node = roots.get(s.charAt(index)); } if (notPinyin.length() > 0) { resultPinyins.add(notPinyin.toString()); notPinyin = new StringBuffer(); } if (index == s.length()) { return resultPinyins; } StringBuffer bufPinyin = new StringBuffer(); bufPinyin.append(s.charAt(index)); if (index == s.length() - 1) { resultPinyins.add(bufPinyin.toString()); } for (int i = index + 1; i < s.length(); i++) { if (!Character.isLetter(s.charAt(i))) {// 如果不是字母 if (bufPinyin.length() > 0) { resultPinyins.add(bufPinyin.toString()); bufPinyin = new StringBuffer(); } resultPinyins.add(String.valueOf(s.charAt(i))); continue; } PinyinCharNode tempNode = node.getNodeByChar(s.charAt(i)); if (tempNode == null) { if (bufPinyin.length() > 0) resultPinyins.add(bufPinyin.toString()); bufPinyin = new StringBuffer(); bufPinyin.append(s.charAt(i)); node = roots.get(s.charAt(i)); if (i == s.length() - 1) { resultPinyins.add(bufPinyin.toString()); } } else { bufPinyin.append(s.charAt(i)); if (i == s.length() - 1) { resultPinyins.add(bufPinyin.toString()); } node = tempNode; } } } return resultPinyins; }
这个方法我测试了几次,应该没有问题。
附PinyinCharNode.java代码:
public class PinyinCharNode { private PinyinCharNode() { super(); } private char ch; private List<PinyinCharNode> nodes = Collections .synchronizedList(new ArrayList<PinyinCharNode>()); public char getCh() { return ch; } public void setCh(char ch) { this.ch = ch; } public List<PinyinCharNode> getNodes() { return nodes; } public void setNodes(List<PinyinCharNode> nodes) { this.nodes = nodes; } public void addNode(PinyinCharNode node) { this.nodes.add(node); } public PinyinCharNode addNode(char node) { PinyinCharNode p = valueOf(node); addNode(p); return p; } public PinyinCharNode getNodeByChar(char ch) { for (PinyinCharNode node : nodes) { if (ch == node.getCh()) { return node; } } return null; } private PinyinCharNode(char ch) { super(); this.ch = ch; } public static PinyinCharNode valueOf(char ch) { return new PinyinCharNode(ch); } }
PS:本人绝对是新手……本人也绝对是新手文……但属本人原创……高手请飘过……