001    // Copyright 2004, 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.util;
016    
017    import java.util.ArrayList;
018    import java.util.HashMap;
019    import java.util.List;
020    import java.util.Map;
021    
022    import org.apache.hivemind.ApplicationRuntimeException;
023    import org.apache.oro.text.regex.MalformedPatternException;
024    import org.apache.oro.text.regex.MatchResult;
025    import org.apache.oro.text.regex.Pattern;
026    import org.apache.oro.text.regex.PatternCompiler;
027    import org.apache.oro.text.regex.PatternMatcher;
028    import org.apache.oro.text.regex.PatternMatcherInput;
029    import org.apache.oro.text.regex.Perl5Compiler;
030    import org.apache.oro.text.regex.Perl5Matcher;
031    
032    /**
033     * Streamlines the interface to ORO by implicitly constructing the necessary compilers and matchers,
034     * and by caching compiled patterns.
035     * 
036     * @author Howard Lewis Ship
037     * @since 3.0
038     */
039    
040    public class RegexpMatcher
041    {
042        private PatternCompiler _patternCompiler;
043    
044        private PatternMatcher _matcher;
045    
046        private Map _compiledPatterns = new HashMap();
047    
048        private Map _escapedPatternStrings = new HashMap();
049    
050        protected Pattern compilePattern(String pattern)
051        {
052            if (_patternCompiler == null)
053                _patternCompiler = new Perl5Compiler();
054    
055            try
056            {
057                return _patternCompiler.compile(pattern, Perl5Compiler.SINGLELINE_MASK | Perl5Compiler.READ_ONLY_MASK);
058            }
059            catch (MalformedPatternException ex)
060            {
061                throw new ApplicationRuntimeException(ex);
062            }
063        }
064    
065        protected Pattern getCompiledPattern(String pattern)
066        {
067            Pattern result = (Pattern) _compiledPatterns.get(pattern);
068    
069            if (result == null)
070            {
071                result = compilePattern(pattern);
072                _compiledPatterns.put(pattern, result);
073            }
074    
075            return result;
076        }
077    
078        /**
079         * Clears any previously compiled patterns.
080         */
081    
082        public void clear()
083        {
084            _compiledPatterns.clear();
085        }
086    
087        protected PatternMatcher getPatternMatcher()
088        {
089            if (_matcher == null)
090                _matcher = new Perl5Matcher();
091    
092            return _matcher;
093        }
094    
095        public boolean matches(String pattern, String input)
096        {
097            Pattern compiledPattern = getCompiledPattern(pattern);
098    
099            return getPatternMatcher().matches(input, compiledPattern);
100        }
101    
102        public boolean contains(String pattern, String input)
103        {
104            Pattern compiledPattern = getCompiledPattern(pattern);
105    
106            return getPatternMatcher().contains(input, compiledPattern);
107        }
108    
109        public String getEscapedPatternString(String pattern)
110        {
111            String result = (String) _escapedPatternStrings.get(pattern);
112    
113            if (result == null)
114            {
115                result = Perl5Compiler.quotemeta(pattern);
116    
117                _escapedPatternStrings.put(pattern, result);
118            }
119    
120            return result;
121        }
122    
123        /**
124         * Given an input string, finds all matches in an input string for the pattern.
125         * 
126         * @param pattern
127         *            the regexp pattern for matching
128         * @param input
129         *            the string to search for matches within
130         * @return array (possibly empty) of matches
131         * @since 4.0
132         */
133        public RegexpMatch[] getMatches(String pattern, String input)
134        {
135            Pattern compiledPattern = getCompiledPattern(pattern);
136    
137            PatternMatcher matcher = getPatternMatcher();
138            PatternMatcherInput matcherInput = new PatternMatcherInput(input);
139    
140            List matches = new ArrayList();
141    
142            while (matcher.contains(matcherInput, compiledPattern))
143            {
144                MatchResult match = matcher.getMatch();
145    
146                matches.add(new RegexpMatch(match));
147            }
148    
149            return (RegexpMatch[]) matches.toArray(new RegexpMatch[matches.size()]);
150        }
151    
152        /**
153         * Given an input string, finds all matches in an input string for the pattern.
154         * 
155         * @param pattern
156         *            the regexp pattern for matching
157         * @param input
158         *            the string to search for matches within
159         * @param subgroup
160         *            the group (sub-expression) within the pattern to return as a match
161         * @return array (possibly empty) of matching strings
162         */
163        public String[] getMatches(String pattern, String input, int subgroup)
164        {
165            Pattern compiledPattern = getCompiledPattern(pattern);
166    
167            PatternMatcher matcher = getPatternMatcher();
168            PatternMatcherInput matcherInput = new PatternMatcherInput(input);
169    
170            List matches = new ArrayList();
171    
172            while (matcher.contains(matcherInput, compiledPattern))
173            {
174                MatchResult match = matcher.getMatch();
175    
176                String matchedInput = match.group(subgroup);
177    
178                matches.add(matchedInput);
179            }
180    
181            return (String[]) matches.toArray(new String[matches.size()]);
182        }
183    
184    }