95 votes

Existe-t-il un équivalent de java.util.regex pour les modèles de type "glob"?

Est-il un standard (de préférence Apache Commons ou même non-virale) de la bibliothèque pour faire des "glob" type correspond en Java? Lorsque j'ai eu à faire la même en Perl une fois, je viens de changer tous les ". ""\. " , "* "" .*" et "? "" ." et ce genre de chose, mais je me demandais si quelqu'un a fait le travail pour moi.

Question similaire: http://stackoverflow.com/questions/445910/create-regex-from-glob-expression

67voto

finnw Points 24592

Globbing est également prévu pour être implémenté dans Java 7.

Voir FileSystem.getPathMatcher(String) et le didacticiel "Recherche de fichiers" .

52voto

Dave Ray Points 20873

Il n'y a rien d'intégré, mais c'est assez simple de convertir quelque chose de globiste en regex:

 public static String createRegexFromGlob(String glob)
{
    String out = "^";
    for(int i = 0; i < glob.length(); ++i)
    {
        final char c = glob.charAt(i);
        switch(c)
        {
        case '*': out += ".*"; break;
        case '?': out += '.'; break;
        case '.': out += "\\."; break;
        case '\\': out += "\\\\"; break;
        default: out += c;
        }
    }
    out += '$';
    return out;
}
 

cela fonctionne pour moi, mais je ne suis pas sûr qu'il couvre le "standard" global, s'il en existe un :)

Mise à jour de Paul Tomblin: J'ai trouvé un programme Perl qui effectue la conversion globale, et en l'adaptant à Java, je termine avec:

     private String convertGlobToRegEx(String line)
    {
    LOG.info("got line [" + line + "]");
    line = line.trim();
    int strLen = line.length();
    StringBuilder sb = new StringBuilder(strLen);
    // Remove beginning and ending * globs because they're useless
    if (line.startsWith("*"))
    {
        line = line.substring(1);
        strLen--;
    }
    if (line.endsWith("*"))
    {
        line = line.substring(0, strLen-1);
        strLen--;
    }
    boolean escaping = false;
    int inCurlies = 0;
    for (char currentChar : line.toCharArray())
    {
        switch (currentChar)
        {
        case '*':
            if (escaping)
                sb.append("\\*");
            else
                sb.append(".*");
            escaping = false;
            break;
        case '?':
            if (escaping)
                sb.append("\\?");
            else
                sb.append('.');
            escaping = false;
            break;
        case '.':
        case '(':
        case ')':
        case '+':
        case '|':
        case '^':
        case '$':
        case '@':
        case '%':
            sb.append('\\');
            sb.append(currentChar);
            escaping = false;
            break;
        case '\\':
            if (escaping)
            {
                sb.append("\\\\");
                escaping = false;
            }
            else
                escaping = true;
            break;
        case '{':
            if (escaping)
            {
                sb.append("\\{");
            }
            else
            {
                sb.append('(');
                inCurlies++;
            }
            escaping = false;
            break;
        case '}':
            if (inCurlies > 0 && !escaping)
            {
                sb.append(')');
                inCurlies--;
            }
            else if (escaping)
                sb.append("\\}");
            else
                sb.append("}");
            escaping = false;
            break;
        case ',':
            if (inCurlies > 0 && !escaping)
            {
                sb.append('|');
            }
            else if (escaping)
                sb.append("\\,");
            else
                sb.append(",");
            break;
        default:
            escaping = false;
            sb.append(currentChar);
        }
    }
    return sb.toString();
}
 

Je modifie cette réponse plutôt que de créer la mienne parce que cette réponse me met sur la bonne voie.

35voto

Neil Traft Points 6844

Merci à tous ceux qui sont ici pour leurs contributions. J'ai écrit une conversion plus complète que toutes les réponses précédentes:

 /**
 * Converts a standard POSIX Shell globbing pattern into a regular expression
 * pattern. The result can be used with the standard {@link java.util.regex} API to
 * recognize strings which match the glob pattern.
 * <p/>
 * See also, the POSIX Shell language:
 * http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_13_01
 * 
 * @param pattern A glob pattern.
 * @return A regex pattern to recognize the given glob pattern.
 */
public static final String convertGlobToRegex(String pattern) {
    StringBuilder sb = new StringBuilder(pattern.length());
    int inGroup = 0;
    int inClass = 0;
    int firstIndexInClass = -1;
    char[] arr = pattern.toCharArray();
    for (int i = 0; i < arr.length; i++) {
        char ch = arr[i];
        switch (ch) {
            case '\\':
                if (++i >= arr.length) {
                    sb.append('\\');
                } else {
                    char next = arr[i];
                    switch (next) {
                        case ',':
                            // escape not needed
                            break;
                        case 'Q':
                        case 'E':
                            // extra escape needed
                            sb.append('\\');
                        default:
                            sb.append('\\');
                    }
                    sb.append(next);
                }
                break;
            case '*':
                if (inClass == 0)
                    sb.append(".*");
                else
                    sb.append('*');
                break;
            case '?':
                if (inClass == 0)
                    sb.append('.');
                else
                    sb.append('?');
                break;
            case '[':
                inClass++;
                firstIndexInClass = i+1;
                sb.append('[');
                break;
            case ']':
                inClass--;
                sb.append(']');
                break;
            case '.':
            case '(':
            case ')':
            case '+':
            case '|':
            case '^':
            case '$':
            case '@':
            case '%':
                if (inClass == 0 || (firstIndexInClass == i && ch == '^'))
                    sb.append('\\');
                sb.append(ch);
                break;
            case '!':
                if (firstIndexInClass == i)
                    sb.append('^');
                else
                    sb.append('!');
                break;
            case '{':
                inGroup++;
                sb.append('(');
                break;
            case '}':
                inGroup--;
                sb.append(')');
                break;
            case ',':
                if (inGroup > 0)
                    sb.append('|');
                else
                    sb.append(',');
                break;
            default:
                sb.append(ch);
        }
    }
    return sb.toString();
}
 

Et les tests unitaires pour prouver que cela fonctionne:

 /**
 * @author Neil Traft
 */
public class StringUtils_ConvertGlobToRegex_Test {

    @Test
    public void star_becomes_dot_star() throws Exception {
        assertEquals("gl.*b", StringUtils.convertGlobToRegex("gl*b"));
    }

    @Test
    public void escaped_star_is_unchanged() throws Exception {
        assertEquals("gl\\*b", StringUtils.convertGlobToRegex("gl\\*b"));
    }

    @Test
    public void question_mark_becomes_dot() throws Exception {
        assertEquals("gl.b", StringUtils.convertGlobToRegex("gl?b"));
    }

    @Test
    public void escaped_question_mark_is_unchanged() throws Exception {
        assertEquals("gl\\?b", StringUtils.convertGlobToRegex("gl\\?b"));
    }

    @Test
    public void character_classes_dont_need_conversion() throws Exception {
        assertEquals("gl[-o]b", StringUtils.convertGlobToRegex("gl[-o]b"));
    }

    @Test
    public void escaped_classes_are_unchanged() throws Exception {
        assertEquals("gl\\[-o\\]b", StringUtils.convertGlobToRegex("gl\\[-o\\]b"));
    }

    @Test
    public void negation_in_character_classes() throws Exception {
        assertEquals("gl[^a-n!p-z]b", StringUtils.convertGlobToRegex("gl[!a-n!p-z]b"));
    }

    @Test
    public void nested_negation_in_character_classes() throws Exception {
        assertEquals("gl[[^a-n]!p-z]b", StringUtils.convertGlobToRegex("gl[[!a-n]!p-z]b"));
    }

    @Test
    public void escape_carat_if_it_is_the_first_char_in_a_character_class() throws Exception {
        assertEquals("gl[\\^o]b", StringUtils.convertGlobToRegex("gl[^o]b"));
    }

    @Test
    public void metachars_are_escaped() throws Exception {
        assertEquals("gl..*\\.\\(\\)\\+\\|\\^\\$\\@\\%b", StringUtils.convertGlobToRegex("gl?*.()+|^$@%b"));
    }

    @Test
    public void metachars_in_character_classes_dont_need_escaping() throws Exception {
        assertEquals("gl[?*.()+|^$@%]b", StringUtils.convertGlobToRegex("gl[?*.()+|^$@%]b"));
    }

    @Test
    public void escaped_backslash_is_unchanged() throws Exception {
        assertEquals("gl\\\\b", StringUtils.convertGlobToRegex("gl\\\\b"));
    }

    @Test
    public void slashQ_and_slashE_are_escaped() throws Exception {
        assertEquals("\\\\Qglob\\\\E", StringUtils.convertGlobToRegex("\\Qglob\\E"));
    }

    @Test
    public void braces_are_turned_into_groups() throws Exception {
        assertEquals("(glob|regex)", StringUtils.convertGlobToRegex("{glob,regex}"));
    }

    @Test
    public void escaped_braces_are_unchanged() throws Exception {
        assertEquals("\\{glob\\}", StringUtils.convertGlobToRegex("\\{glob\\}"));
    }

    @Test
    public void commas_dont_need_escaping() throws Exception {
        assertEquals("(glob,regex),", StringUtils.convertGlobToRegex("{glob\\,regex},"));
    }

}
 

10voto

Adam Gent Points 15055

Il y a quelques bibliothèques qui ne Glob-comme le modèle de correspondance qui sont plus modernes que ceux énumérés:

Il Y A Des Fourmis Répertoire Scanner Et Ressorts AntPathMatcher

Je recommande à la fois sur les autres solutions depuis Ant Style d'Expansion a à peu près devenu la norme boule de syntaxe dans le monde Java (Hudson, le Printemps, la Fourmi et je pense que Maven).

5voto

Tony Edgecombe Points 2142

Ceci est une simple implémentation Glob qui gère * et? dans le motif

 public class GlobMatch {
    private String text;
    private String pattern;

    public boolean match(String text, String pattern) {
    	this.text = text;
    	this.pattern = pattern;

    	return matchCharacter(0, 0);
    }

    private boolean matchCharacter(int patternIndex, int textIndex) {
    	if (patternIndex >= pattern.length()) {
    		return false;
    	}

    	switch(pattern.charAt(patternIndex)) {
    		case '?':
    			// Match any character
    			if (textIndex >= text.length()) {
    				return false;
    			}
    			break;

    		case '*':
    			// * at the end of the pattern will match anything
    			if (patternIndex + 1 >= pattern.length() || textIndex >= text.length()) {
    				return true;
    			}

    			// Probe forward to see if we can get a match
    			while (textIndex < text.length()) {
    				if (matchCharacter(patternIndex + 1, textIndex)) {
    					return true;
    				}
    				textIndex++;
    			}

    			return false;

    		default:
    			if (textIndex >= text.length()) {
    				return false;
    			}

    			String textChar = text.substring(textIndex, textIndex + 1);
    			String patternChar = pattern.substring(patternIndex, patternIndex + 1);

    			// Note the match is case insensitive
    			if (textChar.compareToIgnoreCase(patternChar) != 0) {
    				return false;
    			}
    	}

    	// End of pattern and text?
    	if (patternIndex + 1 >= pattern.length() && textIndex + 1 >= text.length()) {
    		return true;
    	}

    	// Go on to match the next character in the pattern
    	return matchCharacter(patternIndex + 1, textIndex + 1);
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X