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 */ 017package org.apache.commons.validator.routines; 018 019import java.io.Serializable; 020import java.util.regex.Pattern; 021import 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 * </p> 032 * <pre> 033 * <code> 034 * String[] regexs = new String[] {...}; 035 * RegexValidator validator = new RegexValidator(regexs, false); 036 * </code> 037 * </pre> 038 * 039 * <ul> 040 * <li>Validate <code>true</code> or <code>false</code>:</li> 041 * <li> 042 * <ul> 043 * <li><code>boolean valid = validator.isValid(value);</code></li> 044 * </ul> 045 * </li> 046 * <li>Validate returning an aggregated String of the matched groups:</li> 047 * <li> 048 * <ul> 049 * <li><code>String result = validator.validate(value);</code></li> 050 * </ul> 051 * </li> 052 * <li>Validate returning the matched groups:</li> 053 * <li> 054 * <ul> 055 * <li><code>String[] result = validator.match(value);</code></li> 056 * </ul> 057 * </li> 058 * </ul> 059 * 060 * <b>Note that patterns are matched against the entire input.</b> 061 * 062 * <p> 063 * Cached instances pre-compile and re-use {@link Pattern}(s) - which according 064 * to the {@link Pattern} API are safe to use in a multi-threaded environment. 065 * </p> 066 * 067 * @version $Revision$ 068 * @since Validator 1.4 069 */ 070public class RegexValidator implements Serializable { 071 072 private static final long serialVersionUID = -8832409930574867162L; 073 074 private final Pattern[] patterns; 075 076 /** 077 * Construct a <i>case sensitive</i> validator for a single 078 * regular expression. 079 * 080 * @param regex The regular expression this validator will 081 * validate against 082 */ 083 public RegexValidator(String regex) { 084 this(regex, true); 085 } 086 087 /** 088 * Construct a validator for a single regular expression 089 * with the specified case sensitivity. 090 * 091 * @param regex The regular expression this validator will 092 * validate against 093 * @param caseSensitive when <code>true</code> matching is <i>case 094 * sensitive</i>, otherwise matching is <i>case in-sensitive</i> 095 */ 096 public RegexValidator(String regex, boolean caseSensitive) { 097 this(new String[] {regex}, caseSensitive); 098 } 099 100 /** 101 * Construct a <i>case sensitive</i> validator that matches any one 102 * of the set of regular expressions. 103 * 104 * @param regexs The set of regular expressions this validator will 105 * validate against 106 */ 107 public RegexValidator(String[] regexs) { 108 this(regexs, true); 109 } 110 111 /** 112 * Construct a validator that matches any one of the set of regular 113 * expressions with the specified case sensitivity. 114 * 115 * @param regexs The set of regular expressions this validator will 116 * validate against 117 * @param caseSensitive when <code>true</code> matching is <i>case 118 * sensitive</i>, otherwise matching is <i>case in-sensitive</i> 119 */ 120 public RegexValidator(String[] regexs, boolean caseSensitive) { 121 if (regexs == null || regexs.length == 0) { 122 throw new IllegalArgumentException("Regular expressions are missing"); 123 } 124 patterns = new Pattern[regexs.length]; 125 int flags = (caseSensitive ? 0: Pattern.CASE_INSENSITIVE); 126 for (int i = 0; i < regexs.length; i++) { 127 if (regexs[i] == null || regexs[i].length() == 0) { 128 throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); 129 } 130 patterns[i] = Pattern.compile(regexs[i], flags); 131 } 132 } 133 134 /** 135 * Validate a value against the set of regular expressions. 136 * 137 * @param value The value to validate. 138 * @return <code>true</code> if the value is valid 139 * otherwise <code>false</code>. 140 */ 141 public boolean isValid(String value) { 142 if (value == null) { 143 return false; 144 } 145 for (int i = 0; i < patterns.length; i++) { 146 if (patterns[i].matcher(value).matches()) { 147 return true; 148 } 149 } 150 return false; 151 } 152 153 /** 154 * Validate a value against the set of regular expressions 155 * returning the array of matched groups. 156 * 157 * @param value The value to validate. 158 * @return String array of the <i>groups</i> matched if 159 * valid or <code>null</code> if invalid 160 */ 161 public String[] match(String value) { 162 if (value == null) { 163 return null; 164 } 165 for (int i = 0; i < patterns.length; i++) { 166 Matcher matcher = patterns[i].matcher(value); 167 if (matcher.matches()) { 168 int count = matcher.groupCount(); 169 String[] groups = new String[count]; 170 for (int j = 0; j < count; j++) { 171 groups[j] = matcher.group(j+1); 172 } 173 return groups; 174 } 175 } 176 return null; 177 } 178 179 180 /** 181 * Validate a value against the set of regular expressions 182 * returning a String value of the aggregated groups. 183 * 184 * @param value The value to validate. 185 * @return Aggregated String value comprised of the 186 * <i>groups</i> matched if valid or <code>null</code> if invalid 187 */ 188 public String validate(String value) { 189 if (value == null) { 190 return null; 191 } 192 for (int i = 0; i < patterns.length; i++) { 193 Matcher matcher = patterns[i].matcher(value); 194 if (matcher.matches()) { 195 int count = matcher.groupCount(); 196 if (count == 1) { 197 return matcher.group(1); 198 } 199 StringBuilder buffer = new StringBuilder(); 200 for (int j = 0; j < count; j++) { 201 String component = matcher.group(j+1); 202 if (component != null) { 203 buffer.append(component); 204 } 205 } 206 return buffer.toString(); 207 } 208 } 209 return null; 210 } 211 212 /** 213 * Provide a String representation of this validator. 214 * @return A String representation of this validator 215 */ 216 @Override 217 public String toString() { 218 StringBuilder buffer = new StringBuilder(); 219 buffer.append("RegexValidator{"); 220 for (int i = 0; i < patterns.length; i++) { 221 if (i > 0) { 222 buffer.append(","); 223 } 224 buffer.append(patterns[i].pattern()); 225 } 226 buffer.append("}"); 227 return buffer.toString(); 228 } 229 230}