Оптимизация нескольких RegEx в коде Java - PullRequest
2 голосов
/ 24 ноября 2011

Упомянутый ниже RegEx очень плохо работает на очень большой строке или более 2000 строк.В основном Java String состоит из сценария PL / SQL.

1 - Заменить каждое вхождение символа-разделителя, например знак ||,! = Или>, пробелом до и после символов.Это занимает бесконечное время и никогда не заканчивается, поэтому время не может быть записано.

// Delimiting characters for SQLPlus
private static final String[] delimiters = { "\\|\\|", "=>", ":=", "!=", "<>", "<", ">", "\\(", "\\)", "!", ",", "\\+", "-", "=", "\\*", "\\|" };


for (int i = 0; i < delimiters.length; i++) {
    script = script.replaceAll(delimiters[i], " " + delimiters[i] + " ");
}

2- Следующий шаблон ищет все вхождения прямой косой черты / кроме тех, которым предшествует *.Это означает, что не ищите косую черту в синтаксисе блочных комментариев.Это займет около 103 секунд для 2000 строк строки.

Pattern p = Pattern.compile("([^\\*])([\\/])([^\\*])");
Matcher m = p.matcher(script);
while (m.find()) {
    script = script.replaceAll(m.group(2), " " + m.group(2) + " ");
}

3- Удалите все пробелы из даты или в формате даты

Pattern p = Pattern.compile("(?i)(\\w{1,2}) +/ +(\\w{1,2}) +/ +(\\w{2,4})");
// Create a matcher with an input string
Matcher m = p.matcher(script);
while (m.find()) {
    part1 = script.substring(0, m.start());
    part2 = script.substring(m.end());
    script = part1 + m.group().replaceAll("[ \t]+", "") + part2;
    m = p.matcher(script);
}

Есть ли способ оптимизировать всетри RegEx, чтобы они занимали меньше времени?

Спасибо

Али

Ответы [ 3 ]

2 голосов
/ 24 ноября 2011

Я отвечу на первый вопрос.

Вы можете объединить все это в одну операцию замены регулярного выражения:

script = script.replaceAll("\\|\\||=>|[:!]=|<>|[<>()!,+=*|-]", " $0 ");

Объяснение:

\|\|            # Match ||
|               # or
=>              # =>
|               # or
[:!]=           # := or !=
|               # or
<>              # <>
|               # or
[<>()!,+=*|-]   # <, >, (, ), !, comma, +, =, *, | or -
1 голос
/ 24 ноября 2011

Это не регулярные выражения, вызывающие вашу проблему с производительностью, это тот факт, что вы делаете много проходов по тексту и постоянно создаете новые объекты Pattern.И не только производительность страдает, как отметил Тим;когда вы делаете это, слишком легко испортить результаты предыдущих проходов.

На самом деле, я предполагаю, что эти лишние пробелы в датах - просто побочный эффект ваших других замен.Если это так, вот способ, которым вы можете сделать все замены за один проход, без добавления нежелательных символов:

static String doReplace(String input)
{
  String regex = 
      "/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/|"      // a comment
    + "\\b\\d{2}/\\d{2}/\\d{2,4}\\b|"         // a date
    + "(/|\\|\\||=>|[:!]=|<>|[<>()!,+=*|-])"; // an operator

  Matcher m = Pattern.compile(regex).matcher(input);
  StringBuffer sb = new StringBuffer();
  while (m.find())
  {
     // if we found an operator, replace it
    if (m.start(1) != -1)
    {
      m.appendReplacement(sb, " $1 ");
    }
  }
  m.appendTail(sb);
  return sb.toString();
}

см. Онлайн-демонстрацию

Хитрость в том, что если вы не позвоните appendReplacement(), позиция совпадения не будет обновлена, поэтому, как будто совпадение не произошло.Поскольку я их игнорирую, комментарии и даты вставляются заново вместе с остальной частью несопоставленного текста, и мне не нужно беспокоиться о сопоставлении символов косой черты внутри них.убедитесь, что часть комментария в регулярном выражении находится перед частью оператора.В противном случае ведущий / каждого комментария будет рассматриваться как оператор.

1 голос
/ 24 ноября 2011

Конечно.Ваш второй подход "почти" хорош.Проблема в том, что вы не используете свой шаблон для замены.Когда вы используете str.replaceAll(), вы фактически создаете Pattern экземпляр каждый раз, когда вызываете этот метод.Pattern.compile() вызывается для вас и занимает 90% времени.

Вы должны использовать Matcher.replaceAll().

    String script = "dfgafjd;fjfd;jfd;djf;jds\\fdfdf****\\/";
    String result = script;

    Pattern p = Pattern.compile("[\\*\\/\\\\]"); // write all characters you want to remove here.
    Matcher m = p.matcher(script);
    if (m.find()) {
        result = m.replaceAll("");
    }       
    System.out.println(result);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...