View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.validator.routines;
18  
19  import java.io.Serializable;
20  import java.util.List;
21  import java.util.regex.Matcher;
22  import java.util.regex.Pattern;
23  
24  /**
25   * <b>Regular Expression</b> validation (using the JRE's regular expression support).
26   * <p>
27   * Constructs the validator either for a single regular expression or a set (array) of
28   * regular expressions. By default validation is <i>case sensitive</i> but constructors
29   * are provided to allow  <i>case in-sensitive</i> validation. For example to create
30   * a validator which does <i>case in-sensitive</i> validation for a set of regular
31   * expressions:
32   * </p>
33   * <pre>
34   * <code>
35   * String[] regexs = new String[] {...};
36   * RegexValidator validator = new RegexValidator(regexs, false);
37   * </code>
38   * </pre>
39   *
40   * <ul>
41   *   <li>Validate {@code true} or {@code false}:</li>
42   *   <li>
43   *     <ul>
44   *       <li><code>boolean valid = validator.isValid(value);</code></li>
45   *     </ul>
46   *   </li>
47   *   <li>Validate returning an aggregated String of the matched groups:</li>
48   *   <li>
49   *     <ul>
50   *       <li><code>String result = validator.validate(value);</code></li>
51   *     </ul>
52   *   </li>
53   *   <li>Validate returning the matched groups:</li>
54   *   <li>
55   *     <ul>
56   *       <li><code>String[] result = validator.match(value);</code></li>
57   *     </ul>
58   *   </li>
59   * </ul>
60   *
61   * <b>Note that patterns are matched against the entire input.</b>
62   *
63   * <p>
64   * Cached instances pre-compile and re-use {@link Pattern}(s) - which according
65   * to the {@link Pattern} API are safe to use in a multi-threaded environment.
66   * </p>
67   *
68   * @since 1.4
69   */
70  public class RegexValidator implements Serializable {
71  
72      private static final long serialVersionUID = -8832409930574867162L;
73  
74      private final Pattern[] patterns;
75  
76      /**
77       * Constructs a <i>case sensitive</i> validator that matches any one
78       * in the list of regular expressions.
79       *
80       * @param regexs The set of regular expressions this validator will
81       * validate against
82       */
83      RegexValidator(final List<String> regexs) {
84          this(regexs.toArray(new String[] {}), true);
85      }
86  
87      /**
88       * Constructs a <i>case sensitive</i> validator for a single
89       * regular expression.
90       *
91       * @param regex The regular expression this validator will
92       * validate against
93       */
94      public RegexValidator(final String regex) {
95          this(regex, true);
96      }
97  
98      /**
99       * Constructs a <i>case sensitive</i> validator that matches any one
100      * in the array of regular expressions.
101      *
102      * @param regexs The set of regular expressions this validator will
103      * validate against
104      */
105     public RegexValidator(final String... regexs) {
106         this(regexs, true);
107     }
108 
109     /**
110      * Constructs a validator for a single regular expression
111      * with the specified case sensitivity.
112      *
113      * @param regex The regular expression this validator will
114      * validate against
115      * @param caseSensitive when {@code true} matching is <i>case
116      * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
117      */
118     public RegexValidator(final String regex, final boolean caseSensitive) {
119         this(new String[] { regex }, caseSensitive);
120     }
121 
122     /**
123      * Constructs a validator that matches any one of the set of regular
124      * expressions with the specified case sensitivity.
125      *
126      * @param regexs The set of regular expressions this validator will
127      * validate against
128      * @param caseSensitive when {@code true} matching is <i>case
129      * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
130      */
131     public RegexValidator(final String[] regexs, final boolean caseSensitive) {
132         if (regexs == null || regexs.length == 0) {
133             throw new IllegalArgumentException("Regular expressions are missing");
134         }
135         patterns = new Pattern[regexs.length];
136         final int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
137         for (int i = 0; i < regexs.length; i++) {
138             if (regexs[i] == null || regexs[i].isEmpty()) {
139                 throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
140             }
141             patterns[i] = Pattern.compile(regexs[i], flags);
142         }
143     }
144 
145     /**
146      * Gets a copy of the Patterns.
147      *
148      * @return a copy of the Patterns.
149      * @since 1.8
150      */
151     public Pattern[] getPatterns() {
152         return patterns.clone();
153     }
154 
155     /**
156      * Validates a value against the set of regular expressions.
157      *
158      * @param value The value to validate.
159      * @return {@code true} if the value is valid
160      * otherwise {@code false}.
161      */
162     public boolean isValid(final String value) {
163         if (value == null) {
164             return false;
165         }
166         for (final Pattern pattern : patterns) {
167             if (pattern.matcher(value).matches()) {
168                 return true;
169             }
170         }
171         return false;
172     }
173 
174     /**
175      * Validates a value against the set of regular expressions
176      * returning the array of matched groups.
177      *
178      * @param value The value to validate.
179      * @return String array of the <i>groups</i> matched if
180      * valid or <code>null</code> if invalid
181      */
182     public String[] match(final String value) {
183         if (value == null) {
184             return null;
185         }
186         for (final Pattern pattern : patterns) {
187             final Matcher matcher = pattern.matcher(value);
188             if (matcher.matches()) {
189                 final int count = matcher.groupCount();
190                 final String[] groups = new String[count];
191                 for (int j = 0; j < count; j++) {
192                     groups[j] = matcher.group(j + 1);
193                 }
194                 return groups;
195             }
196         }
197         return null;
198     }
199 
200     /**
201      * Provides a String representation of this validator.
202      * @return A String representation of this validator.
203      */
204     @Override
205     public String toString() {
206         final StringBuilder buffer = new StringBuilder();
207         buffer.append("RegexValidator{");
208         for (int i = 0; i < patterns.length; i++) {
209             if (i > 0) {
210                 buffer.append(",");
211             }
212             buffer.append(patterns[i].pattern());
213         }
214         buffer.append("}");
215         return buffer.toString();
216     }
217 
218     /**
219      * Validates a value against the set of regular expressions
220      * returning a String value of the aggregated groups.
221      *
222      * @param value The value to validate.
223      * @return Aggregated String value comprised of the
224      * <i>groups</i> matched if valid or <code>null</code> if invalid
225      */
226     public String validate(final String value) {
227         if (value == null) {
228             return null;
229         }
230         for (final Pattern pattern : patterns) {
231             final Matcher matcher = pattern.matcher(value);
232             if (matcher.matches()) {
233                 final int count = matcher.groupCount();
234                 if (count == 1) {
235                     return matcher.group(1);
236                 }
237                 final StringBuilder buffer = new StringBuilder();
238                 for (int j = 0; j < count; j++) {
239                     final String component = matcher.group(j + 1);
240                     if (component != null) {
241                         buffer.append(component);
242                     }
243                 }
244                 return buffer.toString();
245             }
246         }
247         return null;
248     }
249 
250 }