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 }