Подтвердить что ты не робот

Более быстрые альтернативы для замены метода в Java String?

Тот факт, что метод replace возвращает строковый объект, а не заменяет содержимое данной строки, немного тупое (но понятно, когда вы знаете, что строки неизменяемы в Java). Я делаю большой успех, используя глубокую вложенную замену в некотором коде. Есть ли что-то, что я могу заменить на это, это ускорит работу?

4b9b3361

Ответ 1

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

StringBuilder описывается следующим образом:

"Измененная последовательность символов. Этот класс предоставляет API, совместимый с StringBuffer, но без гарантии синхронизации.

Он имеет replaceappend, insert, delete и др.), и вы можете использовать toString для преобразования его в реальный String.

Ответ 2

Предыдущие сообщения правильные, StringBuilder/StringBuffer - это решение.

Но вы также должны задать вопрос, стоит ли делать замену на больших строках в памяти.

У меня часто есть манипуляции с строками, которые реализованы как поток, поэтому вместо замены в строке и последующей отправки ее в OutputStream, я делаю замену в тот момент, когда я отправляю String в выходной поток. Это работает намного быстрее, чем любая замена.

Это работает намного быстрее, если вы хотите, чтобы эта замена выполняла механизм шаблона. Потоковая передача всегда выполняется быстрее, так как вы потребляете меньше памяти, а если клиенты медленные, вам нужно только генерировать медленные темпы - так что она масштабируется намного лучше.

Ответ 3

Следующий код составляет ок. В 30 раз быстрее, если нет совпадений и в 5 раз быстрее, если есть совпадение.

static String fastReplace( String str, String target, String replacement ) {
    int targetLength = target.length();
    if( targetLength == 0 ) {
        return str;
    }
    int idx2 = str.indexOf( target );
    if( idx2 < 0 ) {
        return str;
    }
    StringBuilder buffer = new StringBuilder( targetLength > replacement.length() ? str.length() : str.length() * 2 );
    int idx1 = 0;
    do {
        buffer.append( str, idx1, idx2 );
        buffer.append( replacement );
        idx1 = idx2 + targetLength;
        idx2 = str.indexOf( target, idx1 );
    } while( idx2 > 0 );
    buffer.append( str, idx1, str.length() );
    return buffer.toString();
}

Ответ 4

Я согласен с вышесказанным. Используйте StringBuffer для обеспечения безопасности потоков и StringBuilder при работе с одиночными потоками.

Ответ 5

Добавляя к ответу @paxdiablo, здесь примерная реализация replaceAll с использованием StringBuffers, которая в 3,7 раза быстрее, чем String.replaceAll():

код:

public static String replaceAll(final String str, final String searchChars, String replaceChars)
{
  if ("".equals(str) || "".equals(searchChars) || searchChars.equals(replaceChars))
  {
    return str;
  }
  if (replaceChars == null)
  {
    replaceChars = "";
  }
  final int strLength = str.length();
  final int searchCharsLength = searchChars.length();
  StringBuilder buf = new StringBuilder(str);
  boolean modified = false;
  for (int i = 0; i < strLength; i++)
  {
    int start = buf.indexOf(searchChars, i);

    if (start == -1)
    {
      if (i == 0)
      {
        return str;
      }
      return buf.toString();
    }
    buf = buf.replace(start, start + searchCharsLength, replaceChars);
    modified = true;

  }
  if (!modified)
  {
    return str;
  }
  else
  {
    return buf.toString();
  }
}

Test Case - выход следующий: (Delta1 = 1917009502; Delta2 = 7241000026):

@Test
public void testReplaceAll() 
{
  String origStr = "1234567890-1234567890-";

  String replacement1 =  StringReplacer.replaceAll(origStr, "0", "a");
  String expectedRep1 = "123456789a-123456789a-";

  String replacement2 =  StringReplacer.replaceAll(origStr, "0", "ab");
  String expectedRep2 = "123456789ab-123456789ab-";

  String replacement3 =  StringReplacer.replaceAll(origStr, "0", "");
  String expectedRep3 = "123456789-123456789-";


  String replacement4 =  StringReplacer.replaceAll(origStr, "012", "a");
  String expectedRep4 = "1234567890-1234567890-";

  String replacement5 =  StringReplacer.replaceAll(origStr, "123", "ab");
  String expectedRep5 = "ab4567890-ab4567890-";

  String replacement6 =  StringReplacer.replaceAll(origStr, "123", "abc");
  String expectedRep6 = "abc4567890-abc4567890-";

  String replacement7 =  StringReplacer.replaceAll(origStr, "123", "abcdd");
  String expectedRep7 = "abcdd4567890-abcdd4567890-";

  String replacement8 =  StringReplacer.replaceAll(origStr, "123", "");
  String expectedRep8 = "4567890-4567890-";

  String replacement9 =  StringReplacer.replaceAll(origStr, "123", "");
  String expectedRep9 = "4567890-4567890-";

  assertEquals(replacement1, expectedRep1);
  assertEquals(replacement2, expectedRep2);
  assertEquals(replacement3, expectedRep3);
  assertEquals(replacement4, expectedRep4);
  assertEquals(replacement5, expectedRep5);
  assertEquals(replacement6, expectedRep6);
  assertEquals(replacement7, expectedRep7);
  assertEquals(replacement8, expectedRep8);
  assertEquals(replacement9, expectedRep9);

  long start1 = System.nanoTime();
  for (long i = 0; i < 10000000L; i++)
  {
    String rep =  StringReplacer.replaceAll(origStr, "123", "abcdd");
  }
  long delta1 = System.nanoTime() -start1;

  long start2= System.nanoTime();

  for (long i = 0; i < 10000000L; i++)
  {
    String rep =  origStr.replaceAll( "123", "abcdd");
  }

  long delta2 = System.nanoTime() -start1;

  assertTrue(delta1 < delta2);

  System.out.printf("Delta1 = %d; Delta2 =%d", delta1, delta2);


}

Ответ 6

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

Возможно, для эффективного использования объекта Matcher можно использовать.

Ответ 7

Просто получите char[] String и повторите его. Используйте временный StringBuilder.

Ищите шаблон, который хотите заменить, итерации, если вы не найдете шаблон, напишите материал, который вы сканировали, в StringBuilder, иначе напишите заменяющий текст на StringBuilder.

Ответ 8

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

Ответ 9

Если вы заменяете одиночные символы, рассмотрите итерацию над вашим символьным массивом, но замените символы с помощью (предварительно созданного) HashMap<Character, Character>().

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

Это примерно в два раза быстрее, чем String.replace(char, char). Обратите внимание, что время, связанное с созданием хэш-карты, не включается в это сравнение.