Есть ли способ сращивания струн?

87

Javascript spliceработает только с массивами. Есть ли аналогичный метод для строк? Или мне следует создать свою собственную функцию?

В substr(), и substring()методы будут возвращать только извлеченную строку и не изменяет исходную строку. Я хочу удалить часть моей строки и применить изменение к исходной строке. Более того, этот метод replace()не будет работать в моем случае, потому что я хочу удалить части, начиная с индекса и заканчивая каким-то другим индексом, точно так же, как то, что я могу сделать с этим splice()методом. Я попытался преобразовать свою строку в массив, но это не изящный метод.

ProllyGeek
источник
str.splitможет быть функция, которую вы ищете: google.com/#q=javascript+string+split
Андерсон Грин
1
Что не так str = str.slice()?
elclanrs
1
Похоже на проблему XY, что именно вы пытаетесь сделать? Строки не передаются по ссылке, в отличие от массивов и объектов, поэтому вы не мутируете строки, вы создаете новые или повторно назначаете новую старую.
elclanrs
6
return string.slice(0, startToSplice) + string.slice(endToSplice);нет?
raina77ow

Ответы:

88

Быстрее разрезать строку дважды, например:

function spliceSlice(str, index, count, add) {
  // We cannot pass negative indexes directly to the 2nd slicing operation.
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }

  return str.slice(0, index) + (add || "") + str.slice(index + count);
}

чем использование разделения с последующим объединением (метод Кумара Харша), например:

function spliceSplit(str, index, count, add) {
  var ar = str.split('');
  ar.splice(index, count, add);
  return ar.join('');
}

Вот jsperf, который сравнивает два и несколько других методов. (jsperf не работает уже несколько месяцев. Предлагайте альтернативы в комментариях.)

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

Луи
источник
3
Вы можете добавить это глобально с помощью: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Просто имейте в виду, что он не работает точно так же, как метод соединения массива, потому что строки неизменяемы (вы не можете изменять их после создания). Таким образом, использование будет примерно таким:var s="ss"; s = s.splice(0,1,"t");
Уильям Нили
@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};будет стандартным для обработки строк, поскольку вы сказали, что он неизменяемый.
Mr. Polywhirl
spliceSlice и spliceSplit функционально не равны из-за того, что Array.prototype.splice принимает отрицательные индексы: jsfiddle.net/sykteho6/5 .
Martijn
1
@Mzialla Спасибо, я добавил код, чтобы об этом позаботиться.
Луи
Создание временных переменных и введение мест для единичных ошибок, не говоря уже о коде, который занимает больше времени для обработки людьми, в отличие от split (""). Splice (...). Join ("") - это компромисс, который заслуживает рассмотрения. Проблема со скоростью возникает только в том случае, если это проблема.
Бен Флетчер,
15

редактировать

Это, конечно, не лучший способ «соединить» строку, я привел это в качестве примера того, как будет реализована эта реализация, что является ошибочным и очень очевидно из split (), splice () и join (). Для гораздо лучшей реализации см . Метод Луи .


Нет, такого понятия не существует String.splice, но вы можете попробовать следующее:

newStr = str.split(''); // or newStr = [...str];
newStr.splice(2,5);
newStr = newStr.join('');

Я понимаю, что здесь нет spliceфункции, как в Arrays, поэтому вам нужно преобразовать строку в массив. Невезение...

кумархарш
источник
в моем случае я работаю над динамической строкой, поэтому мне нужно указать индексы, а не значение символа.
ProllyGeek
Да, к сожалению, это правильно. Но вы можете получить индекс символа, используя String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh
3
Вместо str.split вы можете использовать синтаксис распространения ES6 следующим образом:[...str]
robbie
5

Вот симпатичный маленький карри, который обеспечивает лучшую читаемость (ИМХО):

Сигнатура второй функции идентична Array.prototype.spliceметоду.

function mutate(s) {
    return function splice() {
        var a = s.split('');
        Array.prototype.splice.apply(a, arguments);
        return a.join('');
    };
}

mutate('101')(1, 1, '1');

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

Коди
источник
1
Np. Вы даже можете абстрагироваться от этого, чтобы разрешить, скажем, необязательный 'method'параметр, чтобы вы могли передавать Array.prototype[method]строки и обрабатывать их полностью как массивы. Кроме того , с одним только этим, вы могли бы абстрагировать фактический процесс на другую функцию - и если нет строки, возвращает функцию , которая будет принимать строку и обратного карри: mutate()(1, 1, '1')('101'); Вы даже можете duckType аргументов, чтобы избавить карри от пустого вызова - даже инкапсулировать сам метод. Если вам это нужно, вы можете изучить Command Pattern . Просто плюй сюда.
Cody
3

Я хотел бы предложить более простую альтернативу методам Кумара / Коди и Луи. Во всех запускаемых мною тестах он работает так же быстро, как и метод Луи (см. Тесты скриптов).

String.prototype.splice = function(startIndex,length,insertString){
    return this.substring(0,startIndex) + insertString + this.substring(startIndex + length);
};

Вы можете использовать это так:

var creditCardNumber = "5500000000000004";
var cardSuffix = creditCardNumber.splice(0,12,'****');
console.log(cardSuffix);  // output: ****0004

См. Результаты теста: https://jsfiddle.net/0quz9q9m/5/

Тимоти Кански
источник
вы должны хотя бы сделать `+ (insertString ||" ") +` вместо `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` в отличие от других предложений. Однако
отличный
3

Кажется, существует большая путаница, которая была устранена только в комментариях elclanrs и raina77ow, поэтому позвольте мне опубликовать уточняющий ответ.

Разъяснение

От " string.splice" можно ожидать, что он, как и для массивов:

  • принимает до 3 аргументов: начальная позиция, длина и (необязательно) вставка (строка)
  • возвращает вырезанную часть
  • изменяет исходную строку

Проблема, 3D требование не может быть выполнено , так как строки являются неизменными (связанные с : 1 , 2 ), я нашел самый преданный комментарий здесь :

В JavaScript строки - это примитивные типы значений, а не объекты ( спецификация ). В самом деле, как в ES5, они один из немногих 5 типов значений вместе null, undefined, numberи boolean. Строки присваиваются по значению, а не по ссылке, и передаются как таковые. Таким образом, строки не просто неизменяемы, они представляют собой ценность . Изменение строки "hello"на «быть» "world"похоже на решение, что отныне число 3 будет числом 4 ... это не имеет смысла.

Итак, учитывая это, можно ожидать, что " string.splice" будет только:

  • принимает до 2 аргументов: начальная позиция, длина (вставка не имеет смысла, поскольку строка не изменяется)
  • возвращает вырезанную часть

что и substrделает; или, альтернативно,

  • принимает до 3 аргументов: начальная позиция, длина и (необязательно) вставка (строка)
  • возвращает измененную строку (без вырезанной части и со вставкой)

что является предметом следующего раздела.

Решения

Если вы заботитесь об оптимизации, вам, вероятно, следует использовать реализацию Майка:

String.prototype.splice = function(index, count, add) {
    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Однако обработка индекса за пределами границ может варьироваться. В зависимости от ваших потребностей вам может потребоваться:

    if (index < 0) {
        index += this.length;
        if (index < 0)
            index = 0;
    }
    if (index >= this.length) {
        index -= this.length;
        if (index >= this.length)
            index = this.length - 1;
    }

или даже

    index = index % this.length;
    if (index < 0)
        index = this.length + index;

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

String.prototype.splice = function(index, count, add) {
    var chars = this.split('');
    chars.splice(index, count, add);
    return chars.join('');
}

Производительность

Разница в исполнении резко увеличивается с увеличением длины струны. jsperf показывает , что для строк длиной 10 последнее решение (разделение и соединение) в два раза медленнее, чем первое решение (с использованием среза), для 100-буквенных строк это x5, а для 1000-буквенных строк - x50, в Ops / сек это:

                      10 letters   100 letters   1000 letters
slice implementation    1.25 M       2.00 M         1.91 M
split implementation    0.63 M       0.22 M         0.04 M

обратите внимание, что я изменил 1-й и 2-й аргументы при переходе с 10 букв на 100 (все же я удивлен, что тест для 100 букв выполняется быстрее, чем для 10 букв).

ЯковЛ
источник
2

Просто используйте substr для строки

напр.

var str = "Hello world!";
var res = str.substr(1, str.length);

Результат = привет мир!

Динеш Патил
источник
1

Итак, что бы ни добавляли метод splice к прототипу String, он не может работать прозрачно для спецификации ...

Давайте его расширим:

String.prototype.splice = function(...a){
    for(var r = '', p = 0, i = 1; i < a.length; i+=3)
        r+= this.slice(p, p=a[i-1]) + (a[i+1]||'') + this.slice(p+a[i], p=a[i+2]||this.length);
    return r;
}
  • Каждые 3 группы аргументов "вставляются" в стиле сращивания.
  • Специально, если существует более одной группы из 3 аргументов, конец каждого разреза будет началом следующего.
    • '0123456789'.splice (4,1,' четвертый ', 8,1,' восьмой '); // возвращаем '0123fourth567eighth9'
  • Вы можете удалить или обнулить последний аргумент в каждой группе (которая рассматривается как «нечего вставлять»)
    • '0123456789'.splice (-4,2); // возвращаем '0123459'
  • Вы можете удалить все, кроме 1-го аргумента в последней группе (которая обрабатывается как «вырезать все после 1-й позиции аргумента»)
    • '0123456789'.splice (0,2, null, 3,1, null, 5,2,' / ', 8); // возврат 24/7
  • если вы передаете несколько, вы ДОЛЖНЫ самостоятельно проверять порядок расположения позиций слева направо!
  • И если вы не хотите, вы НЕ ДОЛЖНЫ использовать его так:
    • '0123456789'.splice (4, -3,' что? '); // возврат «0123какого? 123456789»
Федор Тыкмаков
источник
0

Ответ метода Луи в качестве Stringфункции-прототипа:

String.prototype.splice = function(index, count, add) {
  if (index < 0) {
    index = this.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  return this.slice(0, index) + (add || "") + this.slice(index + count);
}

Пример:

 > "Held!".splice(3,0,"lo Worl")
 < "Hello World!"
Майк Годин
источник
0

Метод Луи spliceSlice не работает, когда добавленное значение равно 0 или другие ложные значения, вот исправление:

function spliceSlice(str, index, count, add) {
  if (index < 0) {
    index = str.length + index;
    if (index < 0) {
      index = 0;
    }
  }
  const hasAdd = typeof add !== 'undefined';
  return str.slice(0, index) + (hasAdd ? add : '') + str.slice(index + count);
}
Марюс Марцыалис
источник
0

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

let str = "I need to remove a character from this";
let pos = str.indexOf("character")

if(pos>-1){
  let result = str.slice(0, pos-2) + str.slice(pos, str.length);
  console.log(result) //I need to remove character from this 
}

Мне нужно было удалить символ до / после определенного слова, после того, как вы получите позицию, строка разделена на две, а затем перекомпонована путем гибкого удаления символов с использованием смещения вдоль pos

Рэй Ремнант
источник