001 package org.shiftone.jrat.util.regex; 002 003 004 import org.shiftone.jrat.util.Assert; 005 import org.shiftone.jrat.util.StringUtil; 006 import org.shiftone.jrat.util.log.Logger; 007 008 import java.io.File; 009 010 011 /** 012 * Class matches simple regular expressions of the form: 013 * <li>this* 014 * <li>* is so * 015 * <li>input_file_*.dat 016 * <li>com.ml.gdfs.common.util.text.* 017 * <li>?he q???k br?wn fox 018 * <li>java 1.4.? 019 * 020 * @author jeff@shiftone.org (Jeff Drost) 021 */ 022 public class GlobMatcher implements Matcher { 023 024 private static final Logger LOG = Logger.getLogger(GlobMatcher.class); 025 public static final Matcher INCLUDE_ALL = new GlobMatcher("*"); 026 private char[][] patternParts = null; 027 private String pattenString; 028 029 public static Matcher create(String pattenString) { 030 return (pattenString == null) ? Matcher.ALL : new GlobMatcher(pattenString); 031 } 032 033 /** 034 * @param pattenString initializes the matcher with the glob patterm. 035 */ 036 public GlobMatcher(String pattenString) { 037 038 Assert.assertNotNull("pattenString", pattenString); 039 040 this.pattenString = pattenString; 041 this.patternParts = getPatternParts(pattenString); 042 } 043 044 045 public boolean isMatch(String inputString) { 046 047 Assert.assertNotNull("inputString", inputString); 048 049 return isMatch(inputString, patternParts); 050 } 051 052 053 /** 054 * simple method to allow glob matcher to implement FilenameFilter. Matches 055 * name only. 056 */ 057 public boolean accept(File dir, String name) { 058 return isMatch(name); 059 } 060 061 062 private static char[][] getPatternParts(String pattenString) { 063 064 String[] sections = StringUtil.tokenize(pattenString, "*", true); 065 char[][] patternParts = new char[sections.length][]; 066 067 for (int i = 0; i < sections.length; i++) { 068 patternParts[i] = sections[i].toCharArray(); 069 } 070 071 return patternParts; 072 } 073 074 075 /** 076 * <b>used by unit tests only</b> 077 */ 078 public static boolean isMatch(String inputString, String pattenString) { 079 return isMatch(inputString, getPatternParts(pattenString)); 080 } 081 082 083 /** 084 * Method isMatch 085 */ 086 public static boolean isMatch(String input, char[][] patternParts) { 087 088 char[] in = input.toCharArray(); 089 boolean canSkip = false; 090 int currentIndex = 0; 091 092 for (int i = 0; i < patternParts.length; i++) { 093 if (patternParts[i][0] == '*') { 094 canSkip = true; 095 } else { 096 if (canSkip == false) { 097 if (!matchesFixed(in, currentIndex, patternParts[i])) { 098 return false; 099 } 100 } else { 101 int m = nextFixedMatch(in, currentIndex, patternParts[i]); 102 103 if (m == -1) { 104 return false; 105 } else { 106 currentIndex = m + patternParts[i].length; 107 } 108 } 109 110 canSkip = false; 111 } 112 } 113 114 return true; 115 } 116 117 118 /** 119 * <b>used by unit tests only</b> 120 */ 121 public static int nextFixedMatch(String cs, int offSet, String ps) { 122 return nextFixedMatch(cs.toCharArray(), offSet, ps.toCharArray()); 123 } 124 125 126 /** 127 * Method nextFixedMatch 128 */ 129 public static int nextFixedMatch(char[] cs, int offSet, char[] ps) { 130 131 int endIndex = cs.length - ps.length + 1; 132 133 for (int i = offSet; i < endIndex; i++) { 134 if (matchesFixed(cs, i, ps)) { 135 return i; 136 } 137 } 138 139 return -1; 140 } 141 142 143 /** 144 * <b>used by unit tests only</b> 145 */ 146 public static boolean matchesFixed(String cs, int offSet, String ps) { 147 return matchesFixed(cs.toCharArray(), offSet, ps.toCharArray()); 148 } 149 150 151 /** 152 * Method matchesFixed 153 */ 154 public static boolean matchesFixed(char[] cs, int offSet, char[] ps) { 155 156 for (int i = 0; i < ps.length; i++) { 157 int c = i + offSet; 158 159 if (c >= cs.length) { 160 return false; 161 } 162 163 if ((cs[c] != ps[i]) && (ps[i] != '?')) { 164 return false; 165 } 166 } 167 168 return true; 169 } 170 171 172 public String toString() { 173 return "<glob pattern=\"" + pattenString + "\"/>"; 174 } 175 }