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.openstreetmap.josm.data.validation.routines; 018 019import java.util.regex.Matcher; 020import java.util.regex.Pattern; 021 022/** 023 * <b>Regular Expression</b> validation (using JDK 1.4+ regex support). 024 * <p> 025 * Construct the validator either for a single regular expression or a set (array) of 026 * regular expressions. By default validation is <i>case sensitive</i> but constructors 027 * are provided to allow <i>case in-sensitive</i> validation. For example to create 028 * a validator which does <i>case in-sensitive</i> validation for a set of regular 029 * expressions: 030 * <pre> 031 * String[] regexs = new String[] {...}; 032 * RegexValidator validator = new RegexValidator(regexs, false); 033 * </pre> 034 * <ul> 035 * <li>Validate <code>true</code> or <code>false</code>: 036 * <ul> 037 * <li><code>boolean valid = validator.isValid(value);</code></li> 038 * </ul></li> 039 * <li>Validate returning an aggregated String of the matched groups: 040 * <ul> 041 * <li><code>String result = validator.validate(value);</code></li> 042 * </ul></li> 043 * <li>Validate returning the matched groups: 044 * <ul> 045 * <li><code>String[] result = validator.match(value);</code></li> 046 * </ul></li> 047 * </ul> 048 * <p> 049 * Cached instances pre-compile and re-use {@link Pattern}(s) - which according 050 * to the {@link Pattern} API are safe to use in a multi-threaded environment. 051 * 052 * @version $Revision: 1227719 $ $Date: 2012-01-05 18:45:51 +0100 (Thu, 05 Jan 2012) $ 053 * @since Validator 1.4 054 */ 055public class RegexValidator extends AbstractValidator { 056 057 private final Pattern[] patterns; 058 059 /** 060 * Construct a <i>case sensitive</i> validator for a single 061 * regular expression. 062 * 063 * @param regex The regular expression this validator will 064 * validate against 065 */ 066 public RegexValidator(String regex) { 067 this(regex, true); 068 } 069 070 /** 071 * Construct a validator for a single regular expression 072 * with the specified case sensitivity. 073 * 074 * @param regex The regular expression this validator will 075 * validate against 076 * @param caseSensitive when <code>true</code> matching is <i>case 077 * sensitive</i>, otherwise matching is <i>case in-sensitive</i> 078 */ 079 public RegexValidator(String regex, boolean caseSensitive) { 080 this(new String[] {regex}, caseSensitive); 081 } 082 083 /** 084 * Construct a <i>case sensitive</i> validator that matches any one 085 * of the set of regular expressions. 086 * 087 * @param regexs The set of regular expressions this validator will 088 * validate against 089 */ 090 public RegexValidator(String[] regexs) { 091 this(regexs, true); 092 } 093 094 /** 095 * Construct a validator that matches any one of the set of regular 096 * expressions with the specified case sensitivity. 097 * 098 * @param regexs The set of regular expressions this validator will 099 * validate against 100 * @param caseSensitive when <code>true</code> matching is <i>case 101 * sensitive</i>, otherwise matching is <i>case in-sensitive</i> 102 */ 103 public RegexValidator(String[] regexs, boolean caseSensitive) { 104 if (regexs == null || regexs.length == 0) { 105 throw new IllegalArgumentException("Regular expressions are missing"); 106 } 107 patterns = new Pattern[regexs.length]; 108 int flags = caseSensitive ? 0 : Pattern.CASE_INSENSITIVE; 109 for (int i = 0; i < regexs.length; i++) { 110 if (regexs[i] == null || regexs[i].isEmpty()) { 111 throw new IllegalArgumentException("Regular expression[" + i + "] is missing"); 112 } 113 patterns[i] = Pattern.compile(regexs[i], flags); 114 } 115 } 116 117 /** 118 * Validate a value against the set of regular expressions. 119 * 120 * @param value The value to validate. 121 * @return <code>true</code> if the value is valid 122 * otherwise <code>false</code>. 123 */ 124 @Override 125 public boolean isValid(String value) { 126 if (value == null) { 127 return false; 128 } 129 for (int i = 0; i < patterns.length; i++) { 130 if (patterns[i].matcher(value).matches()) { 131 return true; 132 } 133 } 134 return false; 135 } 136 137 /** 138 * Validate a value against the set of regular expressions 139 * returning the array of matched groups. 140 * 141 * @param value The value to validate. 142 * @return String array of the <i>groups</i> matched if 143 * valid or <code>null</code> if invalid 144 */ 145 public String[] match(String value) { 146 if (value == null) { 147 return null; 148 } 149 for (int i = 0; i < patterns.length; i++) { 150 Matcher matcher = patterns[i].matcher(value); 151 if (matcher.matches()) { 152 int count = matcher.groupCount(); 153 String[] groups = new String[count]; 154 for (int j = 0; j < count; j++) { 155 groups[j] = matcher.group(j+1); 156 } 157 return groups; 158 } 159 } 160 return null; 161 } 162 163 164 /** 165 * Validate a value against the set of regular expressions 166 * returning a String value of the aggregated groups. 167 * 168 * @param value The value to validate. 169 * @return Aggregated String value comprised of the 170 * <i>groups</i> matched if valid or <code>null</code> if invalid 171 */ 172 public String validate(String value) { 173 if (value == null) { 174 return null; 175 } 176 for (int i = 0; i < patterns.length; i++) { 177 Matcher matcher = patterns[i].matcher(value); 178 if (matcher.matches()) { 179 int count = matcher.groupCount(); 180 if (count == 1) { 181 return matcher.group(1); 182 } 183 StringBuilder buffer = new StringBuilder(); 184 for (int j = 0; j < count; j++) { 185 String component = matcher.group(j+1); 186 if (component != null) { 187 buffer.append(component); 188 } 189 } 190 return buffer.toString(); 191 } 192 } 193 return null; 194 } 195 196 /** 197 * Provide a String representation of this validator. 198 * @return A String representation of this validator 199 */ 200 @Override 201 public String toString() { 202 StringBuilder buffer = new StringBuilder(); 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}