Czy istnieje metoda łączenia strun?


87

Javascript splicedziała tylko z tablicami. Czy istnieje podobna metoda dla stringów? A może powinienem utworzyć własną funkcję niestandardową?

Te substr()i substring()metody tylko zwrócić wyodrębniony i nie zmieniają oryginalnego łańcucha. To, co chcę zrobić, to usunąć część z mojego ciągu i zastosować zmianę do oryginalnego ciągu. Co więcej, metoda replace()nie zadziała w moim przypadku, ponieważ chcę usunąć części zaczynające się od indeksu, a kończące na jakimś innym indeksie, dokładnie tak, jak mogę zrobić z splice()metodą. Próbowałem przekonwertować mój ciąg na tablicę, ale nie jest to zgrabna metoda.


str.splitmoże to być funkcja, której szukasz: google.com/#q=javascript+string+split
— Anderson Green

1
Co jest nie tak str = str.slice()?
— elclanrs

1
Wygląda na problem XY, co dokładnie próbujesz zrobić? Łańcuchy nie są przekazywane przez referencje, w przeciwieństwie do tablic i obiektów, więc nie modyfikujesz łańcuchów, tworzysz nowe lub ponownie przypisujesz nowy do starego.
— elclanrs


6
return string.slice(0, startToSplice) + string.slice(endToSplice);nie?
— raina77ow

Odpowiedzi:


88

Szybciej jest dwukrotnie przeciąć strunę, na przykład:

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);
}

niż użycie podziału, po którym następuje złączenie (metoda Kumara Harsha), na przykład:

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

Oto plik jsperf, który porównuje te dwie metody i kilka innych. (jsperf nie działa już od kilku miesięcy. Prosimy o sugerowanie alternatyw w komentarzach).

Chociaż powyższy kod implementuje funkcje, które odtwarzają ogólną funkcjonalnośćsplice , optymalizacja kodu dla przypadku przedstawionego przez pytającego (to jest dodanie niczego do zmodyfikowanego ciągu) nie zmienia względnej wydajności różnych metod.


3
Możesz dodać to globalnie za pomocą: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Pamiętaj, że nie działa dokładnie tak samo jak metoda łączenia tablicy, ponieważ łańcuchy są niezmienne (nie możesz ich modyfikować po utworzeniu). Tak więc użycie byłoby następujące:var s="ss"; s = s.splice(0,1,"t");
— William Neely,

@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};byłby standardem do manipulacji napisami, ponieważ powiedziałeś, że jest niezmienny.
— Mr. Polywhirl

spliceSlice i spliceSplit nie są funkcjonalnie równe, ponieważ Array.prototype.splice akceptuje ujemne indeksy: jsfiddle.net/sykteho6/5 .
— Martijn,

1
@Mzialla Dzięki, dodałem kod, aby się tym zająć.
— Louis

Tworzenie zmiennych tymczasowych i wprowadzanie miejsc dla błędów typu off-by-one, nie wspominając o kodzie, którego przetwarzanie zajmuje ludziom więcej czasu niż w przypadku split („”). Splice (...). Join („”) to zasługuje na uwagę. Problem z prędkością jest problemem tylko wtedy, gdy jest problemem.
— Ben Fletcher,

15

Edytować

Nie jest to oczywiście najlepszy sposób na „łączenie” łańcucha, podałem to jako przykład tego, jak wyglądałaby implementacja, która jest wadliwa i bardzo widoczna w przypadku split (), splice () i join (). Aby uzyskać znacznie lepszą implementację, zobacz metodę Louisa .


Nie, nie ma czegoś takiego jak a String.splice, ale możesz spróbować tego:

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

Zdaję sobie sprawę, że nie ma takiej splicefunkcji jak w Arrays, więc musisz przekonwertować ciąg na tablicę. Pech ...


w moim przypadku im pracuję na dynamicznym ciągu, więc muszę określić indeksy, a nie wartość znaku.
— ProllyGeek

Tak, to niestety prawda. Ale możesz uzyskać indeks znaku, używając String.prototype.indexOf as"asdsd".indexOf('s');
— kumarharsh

3
Zamiast używać str.split, możesz użyć składni spreadu ES6 w następujący sposób:[...str]
— robbie Kwietnia

5

Oto ładne, małe curry, które zapewnia lepszą czytelność (IMHO):

Podpis drugiej funkcji jest identyczny z Array.prototype.splicemetodą.

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

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

Wiem, że jest już zaakceptowana odpowiedź, ale mam nadzieję, że jest przydatna.


1
Np. Możesz nawet wyabstrahować to, aby zezwolić, powiedzmy, na opcjonalny 'method'parametr, dzięki czemu możesz przekazać Array.prototype[method]ciągi i traktować je całkowicie jak tablice. Również z tego samego jednego, można streszczenie rzeczywisty proces do innej funkcji - a jeśli nie ma ciąg, powrót funkcję, która będzie miała ciąg i odwrócić curry: mutate()(1, 1, '1')('101'); Możesz nawet duckType argumenty, aby usunąć curry z pustego wywołania - a nawet hermetyzować samą metodę. Jeśli potrzebujesz tych rzeczy, możesz jednak zajrzeć do wzorca poleceń . Po prostu plujcie tutaj.
— Cody

3

Chciałbym zaoferować prostszą alternatywę zarówno dla metody Kumar / Cody, jak i metody Louisa. We wszystkich testach, które przeprowadziłem, działa tak szybko, jak metoda Louisa (patrz testy skrzypiec dla testów porównawczych).

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

Możesz go używać w ten sposób:

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

Zobacz wyniki testu: https://jsfiddle.net/0quz9q9m/5/


powinieneś przynajmniej zrobić `+ (insertString ||" ") +` zamiast `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` w przeciwieństwie do innych sugestii. Świetny przykład użycia
— JakowL

3

Wydaje się, że jest wiele nieporozumień, które zostały rozwiązane tylko w komentarzach elclanrs i raina77ow, więc pozwólcie, że opublikuję wyjaśniającą odpowiedź.

Wyjaśnienie

Z "string.splice ” można by się tego spodziewać, podobnie jak w przypadku tablic:

  • przyjmuje do 3 argumentów: pozycja początkowa, długość i (opcjonalnie) wstawienie (ciąg)
  • zwraca wyciętą część
  • modyfikuje oryginalny ciąg

Problem w tym, że wymaganie 3d nie może zostać spełnione, ponieważ ciągi znaków są niezmienne (powiązane: 1 , 2 ), najbardziej dedykowany komentarz znalazłem tutaj :

W JavaScript łańcuchy są prymitywnymi typami wartości, a nie obiektami ( specyfikacjami ). W rzeczywistości, jak z ES5, są jedną z zaledwie 5 typów wartości obok null, undefined, numberi boolean. Ciągi są przypisywane przez wartość, a nie przez odwołanie i jako takie są przekazywane. W ten sposób ciągi znaków są nie tylko niezmienne, są one wartością . Zmiana ciąg "hello"być "world"jakby uznając, że od teraz numer 3 to numer 4 ... to nie ma sensu.

Tak więc, biorąc to pod uwagę, można oczekiwać, że „ string.splice” tylko:

  • przyjmuje do 2 argumentów: pozycja początkowa, długość (wstawianie nie ma sensu, ponieważ ciąg nie jest zmieniany)
  • zwraca wyciętą część

co jest tym, co substrrobi; lub alternatywnie

  • przyjmuje do 3 argumentów: pozycja początkowa, długość i (opcjonalnie) wstawienie (ciąg)
  • zwraca zmodyfikowany ciąg (bez wyciętej części iz wstawieniem)

co jest tematem następnej sekcji.

Rozwiązania

Jeśli zależy Ci na optymalizacji, prawdopodobnie powinieneś skorzystać z implementacji Mike'a:

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);
}

Traktowanie wskaźnika poza granicami może się jednak różnić. W zależności od potrzeb możesz chcieć:

    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;
    }

lub nawet

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

Jeśli nie zależy Ci na wydajności, możesz dostosować sugestię Kumara, która jest prostsza:

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

Występ

Różnica w wykonaniu drastycznie rośnie wraz z długością struny. jsperf pokazuje , że dla łańcuchów o długości 10 to drugie rozwiązanie (dzielenie i łączenie) jest dwukrotnie wolniejsze niż poprzednie rozwiązanie (z użyciem plasterka), dla 100-literowych łańcuchów to x5, a dla 1000-literowych to x50, w Ops / s to:

                      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

zwróć uwagę, że zmieniłem argumenty 1. i 2. przy przechodzeniu z 10 liter na 100 liter (nadal jestem zaskoczony, że test na 100 liter działa szybciej niż na 10 liter).


2

Po prostu użyj substr jako string

dawny.

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

Wynik = świat ello!


1

Tak więc, niezależnie od dodania metody łączenia do prototypu String, nie można działać przezroczysto zgodnie ze specyfikacją ...

Zróbmy to komuś przedłużyć:

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;
}
  • Co 3 grupy argumentów „wstawiające” w stylu łączenia.
  • Specjalnie, jeśli jest więcej niż jedna grupa 3 argumentów, koniec każdego cięcia będzie początkiem następnego.
    • „0123456789”. Podwójny (4,1, „czwarty”, 8,1, „ósmy”); // zwraca „0123fourth567eighth9”
  • Możesz upuścić lub wyzerować ostatni argument w każdej grupie (traktowany jako „nic do wstawienia”)
    • '0123456789'.plice (-4,2); // zwróć „0123459”
  • Możesz usunąć wszystkie z wyjątkiem pierwszego argumentu w ostatniej grupie (traktowane jako „wytnij wszystko po pierwszej pozycji argumentu”)
    • „0123456789”. Podwójna (0,2, null, 3,1, null, 5,2, „/”, 8); // powrót '24 / 7 '
  • jeśli zdasz wiele, MUSISZ samodzielnie sprawdzić rodzaj pozycji od lewej do prawej!
  • A jeśli nie chcesz, NIE WOLNO go używać w ten sposób:
    • '0123456789'.splice (4, -3,' co? '); // zwraca „0123what? 123456789”

0

Metoda odpowiedzi Louisa , jako Stringfunkcja prototypowa:

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);
}

Przykład:

 > "Held!".splice(3,0,"lo Worl")
 < "Hello World!"

0

Metoda spliceSlice Louisa zawodzi, gdy wartość dodania wynosi 0 lub inne fałszywe wartości, oto poprawka:

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

Rozwiązałem swój problem za pomocą tego kodu, jest to swego rodzaju zamiennik brakującego splotu.

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 
}

Musiałem usunąć znak przed / po pewnym słowie, po uzyskaniu pozycji ciąg jest dzielony na dwie, a następnie ponownie składany przez elastyczne usuwanie znaków za pomocą przesunięcia wzdłuż pos

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.