2 // This software is now distributed according to
\r
3 // the Lesser Gnu Public License. Please see
\r
4 // http://www.gnu.org/copyleft/lesser.txt for
\r
6 // -- Happy Computing!
\r
8 package com.stevesoft.pat;
\r
13 /** This class is a different form of Regex designed to work more
\r
14 like the file matching utility of a Unix shell. It is implemented
\r
15 by some simple string transformations:
\r
18 <tr> <td> FileRegex </td> <td> Regex </td>
\r
19 <tr> <td> * </td><td> .* </td>
\r
20 <tr> <td> . </td><td> \. </td>
\r
21 <tr> <td> { </td><td> (?: </td>
\r
22 <tr> <td> {?! </td><td> (?! </td>
\r
23 <tr> <td> {?= </td><td> (?= </td>
\r
24 <tr> <td> {?? </td><td> (?? </td>
\r
25 <tr> <td> } </td><td> ) </td>
\r
26 <tr> <td> ? </td><td> . </td>
\r
27 <tr> <td> {,} </td><td> (|) </td>
\r
30 Note that a FileRegex pattern always ends with the Regex
\r
31 pattern element "$". If you like to experiment, try making
\r
32 FileRegex's and then printing them out. The toString() method
\r
33 does a decompile of the pattern to a standard Regex. Here are
\r
34 some more complete examples:
\r
37 <tr> <td> FileRegex </td><td> Regex </td>
\r
38 <tr> <td>*.java </td><td> .*\.java$ </td>
\r
39 <tr> <td>*.{java,html} </td><td> .*\.(java|html)$ </td>
\r
40 <tr> <td> foo.[chC] </td><td> foo.[chC]$ </td>
\r
44 public class FileRegex
\r
47 /** Build an unitialized FileRegex. */
\r
53 /** Build a FileRegex form String s. */
\r
54 public FileRegex(String s)
\r
60 /** Compile a new pattern.
\r
61 Throws @exception com.stevesoft.pat.RegSyntax for
\r
62 nonsensical patterns like "[9-0]+" just as Regex does.
\r
63 @see com.stevesoft.pat#compile(java.lang.String)
\r
65 public void compile(String s)
\r
68 String npat = toFileRegex(s);
\r
69 super.compile(npat);
\r
70 if (File.separatorChar == '\\') // MS-DOS
\r
76 /** This is the method required by FileNameFilter.
\r
77 To get a listing of files in the current directory
\r
78 ending in .java, do this:
\r
80 File dot = new File(".");
\r
81 FileRegex java_files = new FileRegex("*.java");
\r
82 String[] file_list = dot.list(java_files);
\r
85 public boolean accept(File dir, String s)
\r
87 if (dirflag != EITHER)
\r
89 File f = new File(s);
\r
90 if (f.isDirectory() && dirflag == NONDIR)
\r
94 if (!f.isDirectory() && dirflag == DIR)
\r
99 return matchAt(s, 0);
\r
103 final static int EITHER = 0, DIR = 1, NONDIR = 2;
\r
105 /** Provides an alternative to File.list -- this
\r
106 separates its argument according to File.pathSeparator.
\r
107 To each path, it splits off a directory -- all characters
\r
108 up to and including the first instance of File.separator --
\r
109 and a file pattern -- the part that comes after the directory.
\r
110 It then produces a list of all the pattern matches on all
\r
111 the paths. Thus "*.java:../*.java" would produce a list of
\r
112 all the java files in this directory and in the ".." directory
\r
113 on a Unix machine. "*.java;..\\*.java" would do the same thing
\r
114 on a Dos machine. */
\r
115 public static String[] list(String f)
\r
117 return list(f, EITHER);
\r
120 static String[] list(String f, int df)
\r
122 //return list_(f,new FileRegex());
\r
123 StringTokenizer st = new StringTokenizer(f, File.pathSeparator);
\r
124 Vector v = new Vector();
\r
125 while (st.hasMoreTokens())
\r
127 String path = st.nextToken();
\r
128 list1(path, v, df, true);
\r
130 String[] sa = new String[v.size()];
\r
135 final static Regex root = new Regex(File.separatorChar == '/' ?
\r
136 "/$" : "(?:.:|)\\\\$");
\r
137 static void list1(String path, Vector v, int df, boolean rec)
\r
139 // if path looks like a/b/c/ or d:\ then add .
\r
140 if (root.matchAt(path, 0))
\r
142 v.addElement(path + ".");
\r
145 File f = new File(path);
\r
146 if (f.getParent() != null && rec)
\r
148 Vector v2 = new Vector();
\r
149 list1(f.getParent(), v2, DIR, true);
\r
150 for (int i = 0; i < v2.size(); i++)
\r
152 String path2 = ( (String) v2.elementAt(i)) +
\r
153 File.separator + f.getName();
\r
154 list1(path2, v, df, false);
\r
159 File base = new File(path);
\r
161 String dir_s = base.getParent();
\r
166 File dir = new File(dir_s);
\r
168 FileRegex fr = new FileRegex(base.getName());
\r
169 if (fr.isLiteral())
\r
171 v.addElement(dir_s + File.separator + base.getName());
\r
175 String[] sa = dir.list(fr);
\r
180 for (int i = 0; i < sa.length; i++)
\r
182 v.addElement(dir_s + File.separator + sa[i]);
\r
187 /** This method takes a file regular expression, and translates it
\r
188 into the type of pattern used by a normal Regex. */
\r
189 public static String toFileRegex(String s)
\r
191 StrPos sp = new StrPos(s, 0);
\r
192 StringBuffer sb = new StringBuffer();
\r
193 if (sp.incMatch("{?e="))
\r
195 char e = sp.thisChar();
\r
197 if (sp.incMatch("}"))
\r
199 sb.append("(?e=" + e + ")^");
\r
203 sb.append("^(?e=");
\r
210 if (File.separatorChar == '\\')
\r
216 sp.dontMatch = false;
\r
218 if (sp.incMatch("?"))
\r
222 else if (sp.incMatch("."))
\r
227 else if (sp.incMatch("{??"))
\r
231 // allow negative lookahead to work
\r
233 else if (sp.incMatch("{?!"))
\r
237 // allow positive lookahead to work
\r
239 else if (sp.incMatch("{?="))
\r
244 else if (sp.incMatch("{"))
\r
249 else if (sp.incMatch("}"))
\r
254 else if (ParenLvl != 0 && sp.incMatch(","))
\r
258 else if (sp.incMatch("*"))
\r
264 sb.append(sp.thisChar());
\r
269 return sb.toString();
\r
272 public boolean isLiteral()
\r
274 Pattern x = thePattern;
\r
275 while (x != null && ! (x instanceof End))
\r
277 if (x instanceof oneChar)
\r
281 else if (x instanceof Skipped)
\r