RegexValidator.java

  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. import java.io.Serializable;
  19. import java.util.List;
  20. import java.util.regex.Matcher;
  21. import java.util.regex.Pattern;

  22. /**
  23.  * <b>Regular Expression</b> validation (using the JRE's regular expression support).
  24.  * <p>
  25.  * Constructs the validator either for a single regular expression or a set (array) of
  26.  * regular expressions. By default validation is <i>case sensitive</i> but constructors
  27.  * are provided to allow  <i>case in-sensitive</i> validation. For example to create
  28.  * a validator which does <i>case in-sensitive</i> validation for a set of regular
  29.  * expressions:
  30.  * </p>
  31.  * <pre>
  32.  * <code>
  33.  * String[] regexs = new String[] {...};
  34.  * RegexValidator validator = new RegexValidator(regexs, false);
  35.  * </code>
  36.  * </pre>
  37.  *
  38.  * <ul>
  39.  *   <li>Validate {@code true} or {@code false}:</li>
  40.  *   <li>
  41.  *     <ul>
  42.  *       <li><code>boolean valid = validator.isValid(value);</code></li>
  43.  *     </ul>
  44.  *   </li>
  45.  *   <li>Validate returning an aggregated String of the matched groups:</li>
  46.  *   <li>
  47.  *     <ul>
  48.  *       <li><code>String result = validator.validate(value);</code></li>
  49.  *     </ul>
  50.  *   </li>
  51.  *   <li>Validate returning the matched groups:</li>
  52.  *   <li>
  53.  *     <ul>
  54.  *       <li><code>String[] result = validator.match(value);</code></li>
  55.  *     </ul>
  56.  *   </li>
  57.  * </ul>
  58.  *
  59.  * <b>Note that patterns are matched against the entire input.</b>
  60.  *
  61.  * <p>
  62.  * Cached instances pre-compile and re-use {@link Pattern}(s) - which according
  63.  * to the {@link Pattern} API are safe to use in a multi-threaded environment.
  64.  * </p>
  65.  *
  66.  * @since 1.4
  67.  */
  68. public class RegexValidator implements Serializable {

  69.     private static final long serialVersionUID = -8832409930574867162L;

  70.     private final Pattern[] patterns;

  71.     /**
  72.      * Constructs a <i>case sensitive</i> validator that matches any one
  73.      * in the list of regular expressions.
  74.      *
  75.      * @param regexs The set of regular expressions this validator will
  76.      * validate against
  77.      */
  78.     RegexValidator(final List<String> regexs) {
  79.         this(regexs.toArray(new String[] {}), true);
  80.     }

  81.     /**
  82.      * Constructs a <i>case sensitive</i> validator for a single
  83.      * regular expression.
  84.      *
  85.      * @param regex The regular expression this validator will
  86.      * validate against
  87.      */
  88.     public RegexValidator(final String regex) {
  89.         this(regex, true);
  90.     }

  91.     /**
  92.      * Constructs a <i>case sensitive</i> validator that matches any one
  93.      * in the array of regular expressions.
  94.      *
  95.      * @param regexs The set of regular expressions this validator will
  96.      * validate against
  97.      */
  98.     public RegexValidator(final String... regexs) {
  99.         this(regexs, true);
  100.     }

  101.     /**
  102.      * Constructs a validator for a single regular expression
  103.      * with the specified case sensitivity.
  104.      *
  105.      * @param regex The regular expression this validator will
  106.      * validate against
  107.      * @param caseSensitive when {@code true} matching is <i>case
  108.      * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
  109.      */
  110.     public RegexValidator(final String regex, final boolean caseSensitive) {
  111.         this(new String[] { regex }, caseSensitive);
  112.     }

  113.     /**
  114.      * Constructs a validator that matches any one of the set of regular
  115.      * expressions with the specified case sensitivity.
  116.      *
  117.      * @param regexs The set of regular expressions this validator will
  118.      * validate against
  119.      * @param caseSensitive when {@code true} matching is <i>case
  120.      * sensitive</i>, otherwise matching is <i>case in-sensitive</i>
  121.      */
  122.     public RegexValidator(final String[] regexs, final boolean caseSensitive) {
  123.         if (regexs == null || regexs.length == 0) {
  124.             throw new IllegalArgumentException("Regular expressions are missing");
  125.         }
  126.         patterns = new Pattern[regexs.length];
  127.         final int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE;
  128.         for (int i = 0; i < regexs.length; i++) {
  129.             final String regex = regexs[i];
  130.             if (regex == null || regex.isEmpty()) {
  131.                 throw new IllegalArgumentException("Regular expression[" + i + "] is missing");
  132.             }
  133.             patterns[i] = Pattern.compile(regex, flags);
  134.         }
  135.     }

  136.     /**
  137.      * Gets a copy of the Patterns.
  138.      *
  139.      * @return a copy of the Patterns.
  140.      * @since 1.8
  141.      */
  142.     public Pattern[] getPatterns() {
  143.         return patterns.clone();
  144.     }

  145.     /**
  146.      * Validates a value against the set of regular expressions.
  147.      *
  148.      * @param value The value to validate.
  149.      * @return {@code true} if the value is valid
  150.      * otherwise {@code false}.
  151.      */
  152.     public boolean isValid(final String value) {
  153.         if (value == null) {
  154.             return false;
  155.         }
  156.         for (final Pattern pattern : patterns) {
  157.             if (pattern.matcher(value).matches()) {
  158.                 return true;
  159.             }
  160.         }
  161.         return false;
  162.     }

  163.     /**
  164.      * Validates a value against the set of regular expressions
  165.      * returning the array of matched groups.
  166.      *
  167.      * @param value The value to validate.
  168.      * @return String array of the <i>groups</i> matched if
  169.      * valid or {@code null} if invalid
  170.      */
  171.     public String[] match(final String value) {
  172.         if (value == null) {
  173.             return null;
  174.         }
  175.         for (final Pattern pattern : patterns) {
  176.             final Matcher matcher = pattern.matcher(value);
  177.             if (matcher.matches()) {
  178.                 final int count = matcher.groupCount();
  179.                 final String[] groups = new String[count];
  180.                 for (int j = 0; j < count; j++) {
  181.                     groups[j] = matcher.group(j + 1);
  182.                 }
  183.                 return groups;
  184.             }
  185.         }
  186.         return null;
  187.     }

  188.     /**
  189.      * Provides a String representation of this validator.
  190.      * @return A String representation of this validator.
  191.      */
  192.     @Override
  193.     public String toString() {
  194.         final StringBuilder buffer = new StringBuilder();
  195.         buffer.append("RegexValidator{");
  196.         for (int i = 0; i < patterns.length; i++) {
  197.             if (i > 0) {
  198.                 buffer.append(",");
  199.             }
  200.             buffer.append(patterns[i].pattern());
  201.         }
  202.         buffer.append("}");
  203.         return buffer.toString();
  204.     }

  205.     /**
  206.      * Validates a value against the set of regular expressions
  207.      * returning a String value of the aggregated groups.
  208.      *
  209.      * @param value The value to validate.
  210.      * @return Aggregated String value comprised of the
  211.      * <i>groups</i> matched if valid or {@code null} if invalid
  212.      */
  213.     public String validate(final String value) {
  214.         if (value == null) {
  215.             return null;
  216.         }
  217.         for (final Pattern pattern : patterns) {
  218.             final Matcher matcher = pattern.matcher(value);
  219.             if (matcher.matches()) {
  220.                 final int count = matcher.groupCount();
  221.                 if (count == 1) {
  222.                     return matcher.group(1);
  223.                 }
  224.                 final StringBuilder buffer = new StringBuilder();
  225.                 for (int j = 0; j < count; j++) {
  226.                     final String component = matcher.group(j + 1);
  227.                     if (component != null) {
  228.                         buffer.append(component);
  229.                     }
  230.                 }
  231.                 return buffer.toString();
  232.             }
  233.         }
  234.         return null;
  235.     }

  236. }