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             final String regex = regexs[i];
139             if (regex == null || regex.isEmpty()) {
140                 throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
141             }
142             patterns[i] = Pattern.compile(regex, flags);
143         }
144     }
145 
146     /**
147      * Gets a copy of the Patterns.
148      *
149      * @return a copy of the Patterns.
150      * @since 1.8
151      */
152     public Pattern[] getPatterns() {
153         return patterns.clone();
154     }
155 
156     /**
157      * Validates a value against the set of regular expressions.
158      *
159      * @param value The value to validate.
160      * @return {@code true} if the value is valid
161      * otherwise {@code false}.
162      */
163     public boolean isValid(final String value) {
164         if (value == null) {
165             return false;
166         }
167         for (final Pattern pattern : patterns) {
168             if (pattern.matcher(value).matches()) {
169                 return true;
170             }
171         }
172         return false;
173     }
174 
175     /**
176      * Validates a value against the set of regular expressions
177      * returning the array of matched groups.
178      *
179      * @param value The value to validate.
180      * @return String array of the <i>groups</i> matched if
181      * valid or {@code null} if invalid
182      */
183     public String[] match(final String value) {
184         if (value == null) {
185             return null;
186         }
187         for (final Pattern pattern : patterns) {
188             final Matcher matcher = pattern.matcher(value);
189             if (matcher.matches()) {
190                 final int count = matcher.groupCount();
191                 final String[] groups = new String[count];
192                 for (int j = 0; j < count; j++) {
193                     groups[j] = matcher.group(j + 1);
194                 }
195                 return groups;
196             }
197         }
198         return null;
199     }
200 
201     /**
202      * Provides a String representation of this validator.
203      * @return A String representation of this validator.
204      */
205     @Override
206     public String toString() {
207         final StringBuilder buffer = new StringBuilder();
208         buffer.append("RegexValidator{");
209         for (int i = 0; i < patterns.length; i++) {
210             if (i > 0) {
211                 buffer.append(",");
212             }
213             buffer.append(patterns[i].pattern());
214         }
215         buffer.append("}");
216         return buffer.toString();
217     }
218 
219     /**
220      * Validates a value against the set of regular expressions
221      * returning a String value of the aggregated groups.
222      *
223      * @param value The value to validate.
224      * @return Aggregated String value comprised of the
225      * <i>groups</i> matched if valid or {@code null} if invalid
226      */
227     public String validate(final String value) {
228         if (value == null) {
229             return null;
230         }
231         for (final Pattern pattern : patterns) {
232             final Matcher matcher = pattern.matcher(value);
233             if (matcher.matches()) {
234                 final int count = matcher.groupCount();
235                 if (count == 1) {
236                     return matcher.group(1);
237                 }
238                 final StringBuilder buffer = new StringBuilder();
239                 for (int j = 0; j < count; j++) {
240                     final String component = matcher.group(j + 1);
241                     if (component != null) {
242                         buffer.append(component);
243                     }
244                 }
245                 return buffer.toString();
246             }
247         }
248         return null;
249     }
250 
251 }