All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.conqat.lib.commons.filesystem.AntPatternUtils Maven / Gradle / Ivy

There is a newer version: 2024.7.2
Show newest version
/*
 * Copyright (c) CQSE GmbH
 *
 * Licensed 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.
 */

package org.conqat.lib.commons.filesystem;

import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.conqat.engine.core.core.ConQATException;
import org.conqat.lib.commons.string.StringUtils;

/**
 * Utility methods for dealing with Ant pattern as defined at
 * ant.apache.org
 * 

* We implement a special version where a trailing '.' can be used to only match files without file * extension (i.e. file names without dot). *

* This class is copied in AntPatternUtils.js and adapted to JavaScript. If any of the code/logic in * this class is changed, please make sure to change it in the JS code as well. */ public class AntPatternUtils { /** Converts an ANT pattern to a regex pattern. */ public static Pattern convertPattern(String antPattern, boolean caseSensitive) throws PatternSyntaxException { antPattern = normalizePattern(antPattern); // ant specialty: trailing '/**' is optional // for example '**/e*/**' will also match foo/entry boolean addTrailAll = false; if (antPattern.endsWith("/**")) { addTrailAll = true; antPattern = StringUtils.stripSuffix(antPattern, "/**"); } StringBuilder patternBuilder = new StringBuilder(); convertPlainPattern(antPattern, patternBuilder); if (addTrailAll) { // the tail pattern is optional (i.e. we do not require the '/'), // but the "**" is only in effect if the '/' occurs patternBuilder.append("(/.*)?"); } return compileRegex(patternBuilder.toString(), antPattern, caseSensitive); } /** Compiles the given regex. */ private static Pattern compileRegex(String regex, String antPattern, boolean caseSensitive) { try { return Pattern.compile(regex, determineRegexFlags(caseSensitive)); } catch (PatternSyntaxException e) { // make pattern syntax exception more understandable PatternSyntaxException patternSyntaxException = new PatternSyntaxException( "Error compiling ANT pattern '" + antPattern + "' to regular expression. " + e.getDescription(), e.getPattern(), e.getIndex()); patternSyntaxException.addSuppressed(e); throw patternSyntaxException; } } /** Returns the flags to be used for the regular expression. */ private static int determineRegexFlags(boolean caseSensitive) { // Use DOTALL flag, as on Unix the file names can contain line breaks int flags = Pattern.DOTALL; if (!caseSensitive) { flags |= Pattern.CASE_INSENSITIVE; } return flags; } /** * Normalizes the given pattern by ensuring forward slashes and mapping trailing slash to '/**'. */ private static String normalizePattern(String antPattern) { antPattern = FileSystemUtils.normalizeSeparators(antPattern); // ant pattern syntax: if a pattern ends with /, then ** is // appended if (antPattern.endsWith("/")) { antPattern += "**"; } return antPattern; } /** * Converts a plain ANT pattern to a regular expression, by replacing special characters, such as * '?', '*', and '**'. The created pattern is appended to the given {@link StringBuilder}. The * pattern must be plain, i.e. all ANT specialties, such as trailing double stars have to be dealt * with beforehand. */ private static void convertPlainPattern(String antPattern, StringBuilder patternBuilder) { for (int i = 0; i < antPattern.length(); ++i) { char c = antPattern.charAt(i); if (c == '?') { patternBuilder.append("[^/]"); } else if (c != '*') { patternBuilder.append(Pattern.quote(Character.toString(c))); } else { i = convertStarSequence(antPattern, patternBuilder, i); } } } /** * Converts a sequence of the ant pattern starting with a star at the given index. Appends the * pattern fragment the builder and returns the index to continue scanning from. */ private static int convertStarSequence(String antPattern, StringBuilder patternBuilder, int index) { boolean doubleStar = isCharAt(antPattern, index + 1, '*'); if (doubleStar) { // if the double star is followed by a slash, the entire // group becomes optional, as we want "**/foo" to also // match a top-level "foo" boolean doubleStarSlash = isCharAt(antPattern, index + 2, '/'); if (doubleStarSlash) { patternBuilder.append("(.*/)?"); return index + 2; } boolean doubleStarDot = isCharAtBeforeSlashOrEnd(antPattern, index + 2, '.'); if (doubleStarDot) { patternBuilder.append("(.*/)?[^/.]*[.]?"); return index + 2; } patternBuilder.append(".*"); return index + 1; } boolean starDot = isCharAtBeforeSlashOrEnd(antPattern, index + 1, '.'); if (starDot) { patternBuilder.append("[^/.]*[.]?"); return index + 1; } patternBuilder.append("[^/]*"); return index; } /** * Returns whether the given position exists in the string and equals the given character, and the * given character is either at the end or right before a slash. */ private static boolean isCharAtBeforeSlashOrEnd(String s, int position, char character) { return isCharAt(s, position, character) && (position + 1 == s.length() || isCharAt(s, position + 1, '/')); } /** * Returns whether the given position exists in the string and equals the given character. */ private static boolean isCharAt(String s, int position, char character) { return position < s.length() && s.charAt(position) == character; } /** * Converts an ANT pattern to a regex pattern. This catches a potential pattern syntax exception and * wraps it into a {@link ConQATException}. */ public static Pattern convertPatternSafe(String antPattern, boolean caseSensitive) throws ConQATException { try { return convertPattern(antPattern, caseSensitive); } catch (PatternSyntaxException e) { throw new ConQATException(e.getMessage(), e); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy