001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.validator.routines;
018    
019    import java.io.Serializable;
020    import java.util.regex.Pattern;
021    import java.util.regex.Matcher;
022    
023    /**
024     * <b>Regular Expression</b> validation (using JDK 1.4+ regex support).
025     * <p>
026     * Construct the validator either for a single regular expression or a set (array) of 
027     * regular expressions. By default validation is <i>case sensitive</i> but constructors
028     * are provided to allow  <i>case in-sensitive</i> validation. For example to create
029     * a validator which does <i>case in-sensitive</i> validation for a set of regular
030     * expressions:
031     * <pre>
032     *         String[] regexs = new String[] {...};
033     *         RegexValidator validator = new RegexValidator(regexs, false);
034     * </pre>
035     * <p>
036     * <ul>
037     *   <li>Validate <code>true</code> or <code>false</code>:</li>
038     *   <ul>
039     *     <li><code>boolean valid = validator.isValid(value);</code></li>
040     *   </ul>
041     *   <li>Validate returning an aggregated String of the matched groups:</li>
042     *   <ul>
043     *     <li><code>String result = validator.validate(value);</code></li>
044     *   </ul>
045     *   <li>Validate returning the matched groups:</li>
046     *   <ul>
047     *     <li><code>String[] result = validator.match(value);</code></li>
048     *   </ul>
049     * </ul>
050     * <p>
051     * Cached instances pre-compile and re-use {@link Pattern}(s) - which according
052     * to the {@link Pattern} API are safe to use in a multi-threaded environment.
053     *
054     * @version $Revision: 595023 $ $Date: 2007-11-14 20:49:23 +0100 (Mi, 14. Nov 2007) $
055     * @since Validator 1.4
056     */
057    public class RegexValidator implements Serializable {
058    
059        private final Pattern[] patterns;
060    
061        /**
062         * Construct a <i>case sensitive</i> validator for a single
063         * regular expression.
064         *
065         * @param regex The regular expression this validator will
066         * validate against
067         */
068        public RegexValidator(String regex) {
069            this(regex, true);
070        }
071    
072        /**
073         * Construct a validator for a single regular expression
074         * with the specified case sensitivity.
075         *
076         * @param regex The regular expression this validator will
077         * validate against
078         * @param caseSensitive when <code>true</code> matching is <i>case
079         * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
080         */
081        public RegexValidator(String regex, boolean caseSensitive) {
082            this(new String[] {regex}, caseSensitive);
083        }
084    
085        /**
086         * Construct a <i>case sensitive</i> validator that matches any one
087         * of the set of regular expressions.
088         *
089         * @param regexs The set of regular expressions this validator will
090         * validate against
091         */
092        public RegexValidator(String[] regexs) {
093            this(regexs, true);
094        }
095    
096        /**
097         * Construct a validator that matches any one of the set of regular
098         * expressions with the specified case sensitivity.
099         *
100         * @param regexs The set of regular expressions this validator will
101         * validate against
102         * @param caseSensitive when <code>true</code> matching is <i>case
103         * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
104         */
105        public RegexValidator(String[] regexs, boolean caseSensitive) {
106            if (regexs == null || regexs.length == 0) {
107                throw new IllegalArgumentException("Regular expressions are missing");
108            }
109            patterns = new Pattern[regexs.length];
110            int flags =  (caseSensitive ? 0: Pattern.CASE_INSENSITIVE);
111            for (int i = 0; i < regexs.length; i++) {
112                if (regexs[i] == null || regexs[i].length() == 0) {
113                    throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
114                }
115                patterns[i] =  Pattern.compile(regexs[i], flags);
116            }
117        }
118    
119        /**
120         * Validate a value against the set of regular expressions.
121         *
122         * @param value The value to validate.
123         * @return <code>true</code> if the value is valid 
124         * otherwise <code>false</code>.
125         */
126        public boolean isValid(String value) {
127            if (value == null) {
128                return false;
129            }
130            for (int i = 0; i < patterns.length; i++) {
131                if (patterns[i].matcher(value).matches()) {
132                    return true;
133                }
134            }
135            return false;
136        }
137    
138        /**
139         * Validate a value against the set of regular expressions
140         * returning the array of matched groups.
141         *
142         * @param value The value to validate.
143         * @return String array of the <i>groups</i> matched if
144         * valid or <code>null</code> if invalid 
145         */
146        public String[] match(String value) {
147            if (value == null) {
148                return null;
149            }
150            for (int i = 0; i < patterns.length; i++) {
151                Matcher matcher = patterns[i].matcher(value);
152                if (matcher.matches()) {
153                    int count = matcher.groupCount();
154                    String[] groups = new String[count];
155                    for (int j = 0; j < count; j++) {
156                        groups[j] = matcher.group(j+1);
157                    }
158                    return groups;
159                }
160            }
161            return null;
162        }
163    
164    
165        /**
166         * Validate a value against the set of regular expressions
167         * returning a String value of the aggregated groups.
168         *
169         * @param value The value to validate.
170         * @return Aggregated String value comprised of the
171         * <i>groups</i> matched if valid or <code>null</code> if invalid
172         */
173        public String validate(String value) {
174            if (value == null) {
175                return null;
176            }
177            for (int i = 0; i < patterns.length; i++) {
178                Matcher matcher = patterns[i].matcher(value);
179                if (matcher.matches()) {
180                    int count = matcher.groupCount();
181                    if (count == 1) {
182                        return matcher.group(1);
183                    } 
184                    StringBuffer buffer = new StringBuffer();
185                    for (int j = 0; j < count; j++) {
186                        String component = matcher.group(j+1);
187                        if (component != null) {
188                            buffer.append(component);
189                        }
190                    }
191                    return buffer.toString();
192                }
193            }
194            return null;
195        }
196    
197        /**
198         * Provide a String representation of this validator.
199         * @return A String representation of this validator
200         */
201        public String toString() {
202            StringBuffer buffer = new StringBuffer();
203            buffer.append("RegexValidator{");
204            for (int i = 0; i < patterns.length; i++) {
205                if (i > 0) {
206                    buffer.append(",");
207                }
208                buffer.append(patterns[i].pattern());
209            }
210            buffer.append("}");
211            return buffer.toString();
212        }
213    
214    }