Перейти к содержимому



  • Вы не можете создать новую тему
  • Авторизуйтесь для ответа в теме
Сообщений в теме: 10

#1
OFFLINE   monter

monter

    Человечище

  • Модераторы
  • 55 сообщений
Задача такая, нужна функция для поиска и замены n-го совпадения. Допустим 2-го. Функция должна быть универсальной, т.е. если задаем ей заменить первое совпадение, меняет первое, если задаем менять третье, то меняет только третье совпадение.
Выжна скорость работы функции, так как строка очень длинная, совпадений шаблона поиска тоже может быть очень много.
Для примера надо заменить 2-e cовпадение CC на 1234
var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
function replaceSTR(str,n){
........
return strNew;
}
var strNEW2 = replaceSTR(str,2);

У кого есть решения или наработки?

#2
OFFLINE   Rey

Rey

    Regular Member

  • Пользователи
  • PipPipPip
  • 134 сообщений

Могу предложить такое решение.

Меня больше интересует для чего ты его применяешь 

var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
var find =  "CC";
var replace = "< ЗАМЕНИЛ >";
var order = 4;

alert(replaceStrOrder(str, find, replace, order));

function replaceStrOrder(str, find, replace, order) {
    
    var num = 1;
    var reg = new RegExp(find, "g");

    while ( (res = reg.exec(str)) != null && num != order) {
        num++;
    }
    return (reg.lastIndex != 0)? (str.substr(0, reg.lastIndex - find.length)  + replace + str.substr(reg.lastIndex)): str;
}

  • pavelusha это нравится

#3
OFFLINE   pavelusha

pavelusha

    Gold Expert

  • Администраторы
  • 533 сообщений
  • Seattle, WA
Rey, решение хорошее, но есть ошибка!
Eсли задать индекс на пример больше чем количество повторений, то происходит замена последнего вхождения. Это неверно.
На пример делаем order=10.
замены не должно происходить так как есть только 6 повторений "CC", но функция заменит последнее вхождение.
 
еще вчера послал Славе решение. Может не на столько емкое по коду, но работает правильно:
var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
var stringReplacement="Pasha";
 
function replaceSTR(sourceSTR, replaceMask, replaceSTR, replaceIndex)
{
    var  i=0;
    var  stringOccuranceindex=-1;
    var t=0;
    while (i<replaceIndex) {
          t = sourceSTR.indexOf(replaceMask, t);
          if (t<0) return sourceSTR;
          stringOccuranceindex = t;
          i++;
          t+=replaceMask.length;
        }
    return sourceSTR.substring(0,stringOccuranceindex)+replaceSTR+sourceSTR.substring(stringOccuranceindex+replaceMask.length,sourceSTR.length);
    }
 
replaceSTR(str, "CC", stringReplacement, 6);
тут если вхождение не найдено или нет вхождения с нужным номером просто возвращается исходная строка.
  • Rey это нравится

#4
OFFLINE   monter

monter

    Человечище

    Топикстартер
  • Модераторы
  • 55 сообщений

Спасибо! тестируем на скорость

var a = Date.now();
for(i = 1; i<=100000; i++){
//replaceSTR(str, "CC", stringReplacement, 6);
replaceStrOrder(str, find, replace, order)
}
var b = Date.now();
var res = b - a;
alert( "Функция выполнялся <"+ res +"> ms." );

  • Rey это нравится

#5
OFFLINE   pavelusha

pavelusha

    Gold Expert

  • Администраторы
  • 533 сообщений
  • Seattle, WA
хм... Интересно как то получается. И главное интересно почему.

запускал несколько раз подряд посмотреть скорость выполнения.
Мой вариант более менее стабильно показывает результат в районе 7700 мс. плюс/минус 50мс
Вариант от Ray варьируется от 7600 до 8000.
Почему может быть такой разброс?

#6
OFFLINE   Rey

Rey

    Regular Member

  • Пользователи
  • PipPipPip
  • 134 сообщений

Вот вариант который не меняет последнее вхождение

function replaceStrOrder(str, find, replace, order) {
  var num = 1;
  var reg = new RegExp(find, "g");
  while ((res = reg.exec(str)) != null && num < order) {
    num++;
  }
  return (reg.lastIndex != 0 && num == order) ? (str.substr(0, reg.lastIndex - find.length) + replace + str.substr(reg.lastIndex)) : str;
}

Но у меня версия от pavelusha стабильно на ~20% быстрее.



#7
OFFLINE   monter

monter

    Человечище

    Топикстартер
  • Модераторы
  • 55 сообщений

я на винде тестирую, запускаю в АЕ, у Rey тоже чуть-чуть быстрее работает. разброс есть, но не значительный. с чем связано, пока не знаю.


Сообщение отредактировал monter: 28 Сентябрь 2015 - 11:39


#8
OFFLINE   Rey

Rey

    Regular Member

  • Пользователи
  • PipPipPip
  • 134 сообщений

Моя функция ускоряется в 35!!! раз если достать определение регулярки из цикла и искать по регулярке

var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
var find = "CC";
var replace = "< ЗАМЕНИЛ >";
var order = 6;

var reg = new RegExp(find, "g");


function replaceStrOrder(str, reg, replace, order) {

  var num = 1;
  
  while ((res = reg.exec(str)) != null && num < order) {
    num++;
  }
  return (reg.lastIndex != 0 && num == order) ? (str.substr(0, reg.lastIndex - reg.source.length) + replace + str.substr(reg.lastIndex)) : str;
}


#9
OFFLINE   pavelusha

pavelusha

    Gold Expert

  • Администраторы
  • 533 сообщений
  • Seattle, WA

Так, вроде немного дело начинает проясняться.

Разница в быстродействии скорее всего из-за разных платформ. Вы тестировали на Windows, я на Mac OS X. На Маке реализация Java своя и, возможно, из за их собственных оптимизаций работает немного по-другому в плане скорости.

 

Второе, это хорошо что ускорилось в 35 раз, и причина понятна, перестало жрать память постоянно создавая объект регулярки, НО! тут есть другой косячок. В принципе для того за чем Monter использует функцию это наверно не важно, но в общем и целом функция написана не совсем корректно с точки зрения пользования. Она плохо инкапсулирована, а именно, она пользует глобальную переменную, чего делать не должна.

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

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



#10
OFFLINE   Rey

Rey

    Regular Member

  • Пользователи
  • PipPipPip
  • 134 сообщений

Нет, у меня глобальные переменные внутри ф-ции не используются. Совпадение имен переменных роли не играет, т.к. внутри ф-ции своя область видимости и переменные переданные как параметры ф-ции будут принадлежать ОВ этой ф-ции.

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

Вот так можно переписать, если пугает совпадение имен:

var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
var find = "CC";
var replace = "< ЗАМЕНИЛ >";
var order = 5;

var reg = new RegExp(find, "g");

var a = Date.now();
for(i = 1; i<=100000; i++){
   
    replaceStrOrder(str, reg, replace, order);
}
var b = Date.now();
var res = b - a;
alert( "Функция выполнялся <"+ res +"> ms." );

function replaceStrOrder(str, regular, replace, order) {

	var num = 1;
	
	while ((res = regular.exec(str)) != null && num < order) {
		num++;
	}
	
	return (regular.lastIndex != 0 && num == order) ? (str.substr(0, regular.lastIndex - res[0].length) + replace + str.substr(regular.lastIndex)) : str;
}


#11
OFFLINE   pavelusha

pavelusha

    Gold Expert

  • Администраторы
  • 533 сообщений
  • Seattle, WA
Rey, продолжаем тестирование. в строке 11 где идет вызов процедуры ставим 
f=replaceStrOrder(str, reg, replace, order);
на пошаговом исполнении цикла видим что первый раз после исполнения переменная имеет правильный вид, на всех последующих вызовах функция возвращает неправильное значение, а именно это строка без изменения.
 
Ради теста перекинул одно из приравниваний за тело цикла.
функция стала работать на 10% быстрее...
 
var str = "ABCCDECCFGHCCJKLMCCNCCOPQRSCCU";
var stringReplacement="Pasha";
 
function replaceSTR(sourceSTR, replaceMask, replaceSTR, replaceIndex)
{
    var  i=0;
    var  stringOccuranceindex=-1;
    var t=0;
    while (i<replaceIndex) {
          t = sourceSTR.indexOf(replaceMask, t);
          if (t<0) return sourceSTR;
          i++;
          t+=replaceMask.length;
        }
        stringOccuranceindex = t-replaceMask.length;
        return sourceSTR.substring(0,stringOccuranceindex)+replaceSTR+sourceSTR.substring(stringOccuranceindex+replaceMask.length,sourceSTR.length);
    }
 
var a = Date.now();
for(i = 1; i<=100000; i++){
f=replaceSTR(str, "CC", stringReplacement, 6);
}
var b = Date.now();
var res = b - a;
alert( "Функция выполнялся <"+ res +"> ms." );
вывод: Java – супер тормозной язык :(




Количество пользователей, читающих эту тему: 0

0 пользователей, 0 гостей, 0 анонимных