Самый быстрый способ выполнить много замен строк в Java - PullRequest
11 голосов
/ 26 ноября 2010

Мне нужно написать какой-то синтаксический анализатор, который получает строку и заменяет определенные наборы символов другими. Код выглядит так:

noHTMLString = noHTMLString.replaceAll("</p>", "\n");
noHTMLString = noHTMLString.replaceAll("<br/>", "\n\n");
noHTMLString = noHTMLString.replaceAll("<br />", "\n\n");
//here goes A LOT of lines like these ones

Функция очень длинная и выполняет множество замен строк. Проблема здесь в том, что это занимает много времени, потому что метод, который он вызывал много раз, замедляет производительность приложения.

Я читал здесь некоторые темы об использовании StringBuilder в качестве альтернативы, но в нем отсутствует метод ReplaceAll и, как отмечается здесь Не страдает ли производительность string.replaceAll () от неизменности строк? метод replaceAll в классе String работает с

Match Pattern & Matcher и Matcher.replaceAll () использует StringBuilder для хранения полученного в итоге значения поэтому я не знаю, действительно ли переключение на StringBuilder сократит время выполнения замен.

Знаете ли вы быстрый способ быстрого замены большого количества строк? Есть ли у вас какие-либо советы по этой проблеме?

Спасибо.

РЕДАКТИРОВАТЬ : Мне нужно создать отчет, в котором есть несколько полей с HTML-текстом. Для каждой строки я вызываю метод, который заменяет все html-теги и специальные символы внутри этих строк. С полным отчетом требуется более 3 минут, чтобы разобрать весь текст. Проблема в том, что мне приходится очень часто вызывать метод

Ответы [ 4 ]

12 голосов
/ 27 ноября 2010

Я обнаружил, что org.apache.commons.lang.StringUtils - самый быстрый, если вы не хотите беспокоиться о StringBuffer.

Вы можете использовать это так:
noHTMLString = StringUtils.replace(noHTMLString, "</p>", "\n");

Я провел тестирование производительности, оно оказалось намного сложнее, чем мое собственное решение StrinBuffer, подобное предложенному @extraneon.

6 голосов
/ 26 ноября 2010

Похоже, что вы там разбираете HTML, вы хотя бы намеревались использовать стороннюю библиотеку вместо повторного изобретения колеса?

4 голосов
/ 26 ноября 2010

Я согласен с Martijn в использовании готового решения вместо того, чтобы разбирать его самостоятельно - в пакете javax.xml есть множество вещей, встроенных в Java. Оптимальным решением было бы использовать XSLT-преобразование для замены, это выглядит как идеальный вариант использования. Однако это сложно.

Чтобы ответить на вопрос, рассматривали ли вы вопрос об использовании библиотек регулярных выражений ? Похоже, у вас есть много разных вещей, которые вы хотите сопоставить, и замените их одной и той же вещью (\ n или пустая строка). Используя регулярные выражения, вы можете быть выражением типа "<br>|<br/>|<br />" или даже более умным, например <br.*?>", для создания объекта соответствия, для которого вы можете вызвать replaceAll.

3 голосов
/ 26 ноября 2010

Я полностью согласен с Мартийном здесь.Выберите правильный инструмент для работы.

Если ваш файл не HTML, но содержит только некоторые токены HTML, есть несколько способов ускорить процесс.

Во-первых, если некоторое количествовходных данных не содержит заменяемых элементов, рассмотрим начало с чего-то вроде:

if (!input.contains('<')) {
    return input;
}

Во-вторых, рассмотрим регулярное выражение:

Pattern p = Pattern.compile( your_regex );

Не создавайте шаблон для каждой отдельной строки replaceAll, но попробуйте объединить их (в регулярном выражении есть оператор ИЛИ) и пусть Pattern оптимизирует регулярное выражение.Используйте скомпилированный шаблон и не компилируйте его при каждом вызове, это довольно дорого.

Если регулярные выражения немного сложны, вы также можете реализовать некоторые быстрее (но потенциально менее читаемые)Замените движок самостоятельно:

StringBuilder result = new StringBuilder(input.length();
for (int i=0; i < input.length(); i++) {
  char c = input.charAt(i);

  if ( c != '<' ) {
    continue;
  }

  int closePos = input.indexOf( '>', i);
  if (closePos == -1) {// not found
    result.append( input.substring(i, input.length());
    return result.toString();
  }
  i = closePos;
  String token = input.substring(i, closePos);
  if ( token.equals( "p/" ) {
    result.append("\\n");
  } else if (token.equals(...)) {
  } else if (...) {
  } 
}
return result.toString();

В этом могут быть некоторые ошибки :)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...