1 import java.util.HashMap;
  2 import java.util.LinkedList;
  3 import java.util.List;
  4 import java.util.Map;
  5 
  6 /** 
  7  * @author Scott
  8  * @date 2013年12月28日 
  9  * @description
 10  */
 11 public class SundySearch {
 12     String text = null;
 13     String pattern = null;
 14     int currentPos = 0;
 15 
 16     /**
 17      * 匹配後的子串第一個字元位置列表
 18      */
 19     List<Integer> matchedPosList = new LinkedList<Integer>();
 20     
 21     /**
 22      * 匹配字元的Map,記錄改匹配字串有哪些char並且每個char最後出現的位移
 23      */
 24     Map<Character, Integer> map = new HashMap<Character, Integer>();
 25 
 26     public SundySearch(String text, String pattern) {
 27         this.text = text;
 28         this.pattern = pattern;
 29         this.initMap();
 30     };
 31 
 32     /**
 33      * Sunday匹配時,用來儲存Pattern中每個字元最後一次出現的位置,從左到右的順序
 34      */
 35     private void initMap() {
 36         for (int i = 0; i < pattern.length(); i++) {
 37             this.map.put(pattern.charAt(i), i);
 38 
 39         }
 40     }
 41 
 42     /**
 43      * 普通的字串遞迴匹配,匹配失敗就前進一位
 44      */
 45     public List<Integer> normalMatch() {
 46         //匹配失敗,繼續往下走
 47         if (!matchFromSpecialPos(currentPos)) {
 48             currentPos += 1;
 49 
 50             if ((text.length() - currentPos) < pattern.length()) {
 51                 return matchedPosList;
 52             }
 53             normalMatch();
 54         } else {
 55             //匹配成功,記錄位置
 56             matchedPosList.add(currentPos);
 57             currentPos += 1;
 58             normalMatch();
 59         }
 60         
 61         return matchedPosList;
 62     }
 63 
 64     /**
 65      * Sunday匹配,假定Text中的K字元的位置為:當前偏移量+Pattern字串長度+1
 66      */
 67     public List<Integer> sundayMatch() {
 68         // 如果沒有匹配成功
 69         if (!matchFromSpecialPos(currentPos)) {
 70             // 如果Text中K字元沒有在Pattern字串中出現,則跳過整個Pattern字串長度
 71             if ((currentPos + pattern.length() + 1) < text.length()
 72                     && !map.containsKey(text.charAt(currentPos + pattern.length() + 1))) {
 73                 currentPos += pattern.length();
 74             }else {
 75                 // 如果Text中K字元在Pattern字串中出現,則將Text中K字元的位置和Pattern字串中的最後一次出現K字元的位置對齊
 76                 if ((currentPos + pattern.length() + 1) > text.length()) {
 77                     currentPos += 1;
 78                 } else {
 79                     currentPos += pattern.length() - (Integer) map.get(text.charAt(currentPos + pattern.length()));
 80                 }
 81             }
 82             
 83             // 匹配完成,返回全部匹配成功的初始位移
 84             if ((text.length() - currentPos) < pattern.length()) {
 85                 return matchedPosList;
 86             }
 87             
 88             sundayMatch();
 89         }else {
 90             // 匹配成功前進一位然後再次匹配
 91             matchedPosList.add(currentPos);
 92             currentPos += 1;
 93             sundayMatch();
 94         }
 95         return matchedPosList;
 96     }
 97 
 98     /**
 99      * 檢查從Text的指定偏移量開始的子串是否和Pattern匹配
100      */
101     public boolean matchFromSpecialPos(int pos) {
102         if ((text.length()-pos) < pattern.length()) {
103             return false;
104         }
105 
106         for (int i = 0; i < pattern.length(); i++) {
107             if (text.charAt(pos + i) == pattern.charAt(i)) {
108                 if (i == (pattern.length()-1)) {
109                     return true;
110                 }
111                 continue;
112             } else {
113                 break;
114             }
115         }
116         
117         return false;
118     }
119 
120     public static void main(String[] args) {
121         SundySearch sundySearch = new SundySearch("hello 啊啊 阿道夫 adfsadfklf adf234masdfsdfdsfdsfdsffwerwrewrerwerwersdf2666sdflsdfk", "adf");
122         
123         long begin = System.nanoTime();
124         System.out.println("NormalMatch:" + sundySearch.normalMatch());
125         System.out.println("NormalMatch:" + (System.nanoTime() - begin));
126         
127         begin = System.nanoTime();
128         System.out.println("SundayMatch:" + sundySearch.sundayMatch());
129         System.out.println("SundayMatch:" + (System.nanoTime() - begin));
130 
131     }
132 }