Существует ли эквивалент java.util.regex для шаблонов типа “шарика”?

Единственным путем я знаю, как должен сделать это индивидуально, например:

setenv CLASSPATH /User/username/newfolder/jarfile.jar:jarfile2.jar:jarfile3.jar:.

Hope, которая помогает!

80
задан Community 23 May 2017 в 12:03
поделиться

7 ответов

Нет ничего встроенного, но довольно просто преобразовать что-то похожее на глобус в регулярное выражение:

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;
}

это работает для меня, но я не уверен, покрывает ли он глобус " standard ", если он есть :)

Обновление Пола Томблина: Я нашел программу на perl, которая выполняет преобразование glob, и адаптируя ее к Java, я получил:

    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();
}

Я редактирую этот ответ, а не делаю мой собственный, потому что этот ответ направил меня на правильный путь.

42
ответ дан 24 November 2019 в 09:55
поделиться

Globbing также планируется для , реализованного в Java 7.

См. FileSystem.getPathMatcher (String) и учебник «Поиск файлов» .

56
ответ дан 24 November 2019 в 09:55
поделиться

Я не знаю о «стандартной» реализации, но знаю о проекте sourceforge, выпущенном под лицензией BSD, в котором реализовано сопоставление глобусов для файлов. Он реализован в одном файле , возможно, вы сможете адаптировать его под свои требования.

2
ответ дан 24 November 2019 в 09:55
поделиться

Между прочим, похоже, что вы проделали это жестким способом в Perl

Это помогает в Perl:

my @files = glob("*.html")
# Or, if you prefer:
my @files = <*.html> 
-1
ответ дан 24 November 2019 в 09:55
поделиться

Это простая реализация Glob, которая обрабатывает * и? в шаблоне

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);
    }
}
5
ответ дан 24 November 2019 в 09:55
поделиться

Давным-давно я выполнял массовую фильтрацию текста с помощью глобусов, поэтому написал небольшой фрагмент кода (15 строк кода, никаких зависимостей, кроме JDK ). Он обрабатывает только '*' (мне было достаточно), но его можно легко расширить на '?'. Это в несколько раз быстрее, чем предварительно скомпилированное регулярное выражение, не требует предварительной компиляции (по сути, это сравнение строки и строки каждый раз, когда сопоставляется шаблон).

Код:

  public static boolean miniglob(String[] pattern, String line) {
    if (pattern.length == 0) return line.isEmpty();
    else if (pattern.length == 1) return line.equals(pattern[0]);
    else {
      if (!line.startsWith(pattern[0])) return false;
      int idx = pattern[0].length();
      for (int i = 1; i < pattern.length - 1; ++i) {
        String patternTok = pattern[i];
        int nextIdx = line.indexOf(patternTok, idx);
        if (nextIdx < 0) return false;
        else idx = nextIdx + patternTok.length();
      }
      if (!line.endsWith(pattern[pattern.length - 1])) return false;
      return true;
    }
  }

Использование:

  public static void main(String[] args) {
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    try {
      // read from stdin space separated text and pattern
      for (String input = in.readLine(); input != null; input = in.readLine()) {
        String[] tokens = input.split(" ");
        String line = tokens[0];
        String[] pattern = tokens[1].split("\\*+", -1 /* want empty trailing token if any */);

        // check matcher performance
        long tm0 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i) {
          miniglob(pattern, line);
        }
        long tm1 = System.currentTimeMillis();
        System.out.println("miniglob took " + (tm1-tm0) + " ms");

        // check regexp performance
        Pattern reptn = Pattern.compile(tokens[1].replace("*", ".*"));
        Matcher mtchr = reptn.matcher(line);
        tm0 = System.currentTimeMillis();
        for (int i = 0; i < 1000000; ++i) {
          mtchr.matches();
        }
        tm1 = System.currentTimeMillis();
        System.out.println("regexp took " + (tm1-tm0) + " ms");

        // check if miniglob worked correctly
        if (miniglob(pattern, line)) {
          System.out.println("+ >" + line);
        }
        else {
          System.out.println("- >" + line);
        }
      }
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

Скопируйте / вставьте из сюда

0
ответ дан 24 November 2019 в 09:55
поделиться

Недавно мне пришлось это сделать, и я использовал \Q и \E, чтобы избежать шаблона глобуса:

private static Pattern getPatternFromGlob(String glob) {
  return Pattern.compile(
    "^" + Pattern.quote(glob)
            .replace("*", "\\E.*\\Q")
            .replace("?", "\\E.\\Q") 
    + "$");
}
6
ответ дан 24 November 2019 в 09:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: