Чи існує метод сплайсингу для рядків?


87

Javascript spliceпрацює лише з масивами. Чи існує подібний метод для рядків? Або я повинен створити власну власну функцію?

Методи substr(), та substring(), повертають лише витягнутий рядок, а не змінюють початковий рядок. Що я хочу зробити, це видалити якусь частину зі свого рядка та застосувати зміни до вихідного рядка. Більше того, метод replace()не буде працювати в моєму випадку, тому що я хочу видалити частини, починаючи від індексу і закінчуючи іншим індексом, точно так само, як я можу робити з splice()методом. Я спробував перетворити свій рядок на масив, але це не акуратний метод.


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 (""). Сплайсинг (...). Join ("") є компромісом, який заслуговує на розгляд. Проблема зі швидкістю є проблемою, лише якщо це проблема.
Бен Флетчер,

15

Редагувати

Це, звичайно, не найкращий спосіб "зростити" рядок, я подав це як приклад того, як буде реалізація, що є недосконалим і дуже очевидним з split (), splice () і join (). Для набагато кращого впровадження див . Метод Луїса .


Ні, такого поняття як не існує String.splice, але ви можете спробувати це:

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

Я розумію, що немає такої spliceфункції, як у масивах, тому вам доведеться перетворити рядок у масив. Пощастило ...


у моєму випадку я працюю над динамічним рядком, тому мені потрібно вказати індекси, а не значення символу.
ProllyGeek

Так, це, на жаль, правильно. Але ви можете отримати індекс символу, використовуючи String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh

3
Замість того, щоб використовувати str.split, ви можете використовувати синтаксис поширення ES6 таким чином:[...str]
Роббі

5

Ось приємний маленький каррі, який забезпечує кращу читабельність (IMHO):

Підпис другої функції ідентичний 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'); Ви навіть можете ввести аргументи, щоб позбутися каррі від порожнього виклику - навіть інкапсулювати сам метод. Якщо вам потрібні ці речі, ви, можливо, захочете вивчити шаблон команд . Тут просто плюють.
Коді,

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

Отже, будь-який метод додавання сплайсингу до прототипу 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'. З'єднання (-4,2); // повернення '0123459'
  • Ви можете скинути всіх, крім 1-го аргументу, в останню групу (що розглядається як "вирізати все після 1-го місця")
    • '0123456789'.splice (0,2, null, 3,1, null, 5,2,' / ', 8); // повернення '24 / 7 '
  • якщо ви проходите кілька, ви ПОВИННІ перевірити сорт позицій зліва направо самостійно!
  • І якщо ви не хочете, НЕ ПОВИННІ використовувати це так:
    • '0123456789'.splice (4, -3,' what? '); // повернення "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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.