package org.codehaus.mojo.animal_sniffer; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import java.util.regex.Pattern; /** * Utility methods to help with regex manipulation. * * @author Stephen Connolly * @since 1.3 */ public final class RegexUtils { /** * The end of a regex literal sequence. * * @since 1.3 */ public static final String REGEX_QUOTE_END = "\\E"; /** * The start of a regex literal sequence. * * @since 1.3 */ public static final String REGEX_QUOTE_START = "\\Q"; /** * Escape the escapes. * * @since 1.3 */ public static final String REGEX_QUOTE_END_ESCAPED = REGEX_QUOTE_END + '\\' + REGEX_QUOTE_END + REGEX_QUOTE_START; private RegexUtils() { throw new IllegalAccessError( "Utility classes should never be instantiated" ); } /** * Takes a string and returns the regex that will match that string exactly. * * @param s The string to match. * @return The regex that will match the string exactly. * @since 1.3 */ public static String quote( String s ) { int i = s.indexOf( REGEX_QUOTE_END ); if ( i == -1 ) { // we're safe as nobody has a crazy \E in the string return REGEX_QUOTE_START + s + REGEX_QUOTE_END; } // damn there's at least one \E in the string StringBuffer sb = new StringBuffer( s.length() + 32 ); // each escape-escape takes 10 chars... // hope there's less than 4 of them sb.append( REGEX_QUOTE_START ); int pos = 0; do { // we are safe from pos to i sb.append( s.substring( pos, i ) ); // now escape-escape sb.append( REGEX_QUOTE_END_ESCAPED ); // move the working start pos = i + REGEX_QUOTE_END.length(); i = s.indexOf( REGEX_QUOTE_END, pos ); } while ( i != -1 ); sb.append( s.substring( pos, s.length() ) ); sb.append( REGEX_QUOTE_END ); return sb.toString(); } /** * Converts a wildcard rule to a regex rule. * * @param wildcardRule the wildcard rule. * @param exactMatch <code>true</code> results in an regex that will match the entire string, while * <code>false</code> will match the start of the string. * @return The regex rule. */ public static String convertWildcardsToRegex( String wildcardRule, boolean exactMatch ) { StringBuffer regex = new StringBuffer(); int index = 0; final int len = wildcardRule.length(); while ( index < len ) { final int nextQ = wildcardRule.indexOf( '?', index ); final int nextS = wildcardRule.indexOf( '*', index ); if ( nextQ == -1 && nextS == -1 ) { regex.append( quote( wildcardRule.substring( index ) ) ); break; } int nextIndex; if ( nextQ == -1 ) { nextIndex = nextS; } else if ( nextS == -1 ) { nextIndex = nextQ; } else { nextIndex = Math.min( nextQ, nextS ); } if ( index < nextIndex ) { // we have some characters to match regex.append( quote( wildcardRule.substring( index, nextIndex ) ) ); } char c = wildcardRule.charAt( nextIndex ); if ( c == '?' ) { regex.append( '.' ); } else { regex.append( ".*" ); } index = nextIndex + 1; } if ( !exactMatch ) { regex.append( ".*" ); } return regex.toString(); } /** * Compiles a pattern matcher using wildcard based matching. * @param wildcard The wildcards rule to match. * @return A pattern to match the supplied wildcards rule. */ public static Pattern compileWildcard( String wildcard ) { return Pattern.compile( convertWildcardsToRegex( wildcard, true ) ); } }