Dizeler için bir ekleme yöntemi var mı?


92

Javascript spliceyalnızca dizilerle çalışır. Dizeler için benzer bir yöntem var mı? Yoksa kendi özel işlevimi mi oluşturmalıyım?

substr()Ve substring()yöntemleri yalnızca çıkarılan dize dönmek ve özgün dize değiştirmez. Yapmak istediğim şey, dizimden bir parça çıkarmak ve değişikliği orijinal dizeye uygulamak. Üstelik yöntem replace()benim durumumda işe yaramayacak çünkü bir dizinden başlayıp başka bir dizinde biten parçaları, splice()yöntemle yapabildiğim gibi kaldırmak istiyorum . Dizimi bir diziye dönüştürmeyi denedim, ancak bu düzgün bir yöntem değil.


str.splitaradığınız işlev olabilir: google.com/#q=javascript+string+split
Anderson Green

1
Neyin var str = str.slice()?
elclanrs

1
Bir XY problemine benziyor, tam olarak ne yapmaya çalışıyorsun? Dizeler ve nesnelerin aksine dizeler referans olarak aktarılmaz, bu nedenle dizeleri değiştirmezsiniz, yenilerini yaratırsınız veya yenisini eskisine yeniden atarsınız.
elclanrs


6
return string.slice(0, startToSplice) + string.slice(endToSplice);, Hayır?
raina77ow

Yanıtlar:


90

Dizeyi şu şekilde iki kez dilimlemek daha hızlıdır:

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

bir bölme ve ardından bir birleştirme kullanmaktan (Kumar Harsh'ın yöntemi), şunun gibi:

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

İşte iki ve birkaç diğer yöntemi karşılaştıran bir jsperf . (jsperf birkaç aydır kullanım dışı. Lütfen yorumlarda alternatifler önerin.)

Yukarıdaki kodun genel işlevselliğini yeniden üreten işlevleri yerine getirmesine rağmen, splicesoruyu soran tarafından sunulan servis talebi için kodun optimize edilmesi (yani, değiştirilen dizeye hiçbir şey eklenmemesi) çeşitli yöntemlerin göreceli performansını değiştirmez.


3
Bunu global olarak şu şekilde ekleyebilirsiniz: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Dizeler değişmez olduğu için dizi ekleme yöntemiyle tam olarak aynı şekilde çalışmadığını unutmayın (oluşturulduktan sonra değiştiremezsiniz). Yani kullanım şöyle olacaktır:var s="ss"; s = s.splice(0,1,"t");
William Neely

@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};değişmez olduğunu söylediğiniz gibi dize manipülasyonu için standart olacaktır.
Bay Polywhirl

spliceSlice ve spliceSplit, Array.prototype.splice negatif indeksleri kabul ettiğinden işlevsel olarak eşit değildir: jsfiddle.net/sykteho6/5 .
Martijn

1
@Mzialla Teşekkürler, bununla ilgilenmek için kod ekledim.
Louis

Geçici değişkenler oluşturmak ve tek tek hatalar için yerler sunmak, insanların bölme ("") yerine işlemesi daha uzun süren koddan bahsetmiyorum bile (""). Ekleme (...). Join (""), dikkate almayı hak ediyor. Hız sorunu, yalnızca bir sorunsa sorun olur.
ballenf

16

Düzenle

Bu elbette bir dizgeyi "birleştirmenin" en iyi yolu değil, bunu uygulamanın nasıl olacağına dair bir örnek olarak vermiştim, bu hatalı ve bir split (), splice () ve join () 'dan açıkça anlaşılıyor. Çok daha iyi bir uygulama için Louis'in yöntemine bakın.


Hayır, a diye bir şey yoktur String.splice, ama şunu deneyebilirsiniz:

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

spliceDizilerde olduğu gibi bir işlev olmadığının farkındayım , bu yüzden dizeyi bir diziye dönüştürmelisiniz. Şanssızlık...


benim durumumda dinamik bir dizge üzerinde çalışıyorum, bu yüzden karakter değerini değil dizinleri belirtmem gerekiyor.
ProllyGeek

Evet, bu maalesef doğru. Ancak String.prototype.indexOf as"asdsd".indexOf('s');
kumarharsh

3
Str.split kullanmak yerine, ES6 yayılma sözdizimini şu şekilde kullanabilirsiniz:[...str]
robbie

5

İşte daha iyi okunabilirlik (IMHO) sağlayan güzel bir küçük Köri:

İkinci işlevin imzası Array.prototype.spliceyöntemle aynıdır .

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

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

Zaten kabul edilmiş bir cevap olduğunu biliyorum, ancak bunun yararlı olduğunu umuyorum.


1
Np. Hatta isteğe bağlı bir 'method'parametreye izin vermek için bunu soyutlayabilirsiniz, böylece bir Array.prototype[method]dizgeyi geçirebilir ve dizeleri tamamen diziler gibi ele alabilirsiniz. Ayrıca, yalnızca bununla, gerçek süreci başka bir işleve soyutlayabilirsiniz - ve dizge yoksa, dizeyi alacak ve köriyi tersine çevirecek bir işlev döndürürsünüz mutate()(1, 1, '1')('101'):; Hatta boş çağrının körisinden kurtulmak için argümanları yazabilirsiniz - hatta bir yöntemi, kendisini de kapsülleyebilirsiniz. Bunlara ihtiyacınız varsa, yine de Komut Modeline bakmak isteyebilirsiniz . Burada sadece tükürmek.
Cody

3

Hem Kumar / Cody hem de Louis yöntemlerine daha basit bir alternatif sunmak istiyorum. Yaptığım tüm testlerde Louis yöntemi kadar hızlı performans gösteriyor (kıyaslamalar için keman testlerine bakın).

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

Bunu şu şekilde kullanabilirsiniz:

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

Test Sonuçlarına Bakın: https://jsfiddle.net/0quz9q9m/5/


, otherwise the third argument is not optional. This implementation also doesn't take care of diğer önerilerden farklı olarak "+ insertString + startIndex <0 " yerine en azından "+ (insertString ||" ") +" yapmalısınız . Yine de harika bir kullanım örneği
YakovL

3

Sadece elclanrs ve raina77ow tarafından yapılan yorumlarda ele alınan çok fazla kafa karışıklığı var gibi görünüyor, bu yüzden açıklayıcı bir cevap göndermeme izin verin.

Açıklama

" string.splice" Den , diziler için olan gibi, bunun olması beklenebilir:

  • 3 adede kadar argüman kabul eder: başlangıç ​​konumu, uzunluk ve (isteğe bağlı olarak) ekleme (dize)
  • kesilen kısmı döndürür
  • orijinal dizeyi değiştirir

Sorun şu ki, dizeler değişmez olduğu için 3d gereksinimi yerine getirilemiyor (ilgili: 1 , 2 ), burada en özel yorumu buldum :

JavaScript'te dizeler ilkel değer türleridir, nesneler değildir ( spec ). Aslında, ES5 itibariyle, bunlar yanında sadece 5 değer türleri birisin null, undefined, numberve boolean. Yaylı tarafından atanır değeri ve değildir referansla ve bu şekilde geçirilir. Dolayısıyla dizeler yalnızca değişmez değil, bir değerdir . Dizeyi "hello"olacak şekilde değiştirmek, "world"bundan sonra 3 sayısının 4 olduğuna karar vermek gibidir ... hiç mantıklı değil.

Dolayısıyla, hesaba katıldığında, " string.splice" şeyinden yalnızca:

  • en fazla 2 argüman kabul eder: başlangıç ​​konumu, uzunluk (dizge değiştirilmediğinden ekleme bir anlam ifade etmez)
  • kesilen kısmı döndürür

ne substryapar; Veya alternatif olarak,

  • 3 adede kadar argüman kabul eder: başlangıç ​​konumu, uzunluk ve (isteğe bağlı olarak) ekleme (dize)
  • değiştirilmiş dizeyi döndürür (kesilen kısım olmadan ve ekleme ile)

sonraki bölümün konusu.

Çözümler

Optimize etmeyi önemsiyorsanız, muhtemelen Mike'ın uygulamasını kullanmalısınız:

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

Bununla birlikte, sınır dışı indeksini tedavi etmek değişebilir. İhtiyaçlarınıza bağlı olarak şunları isteyebilirsiniz:

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

ya da

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

Performansı önemsemiyorsanız, Kumar'ın önerisini uyarlamak isteyebilirsiniz, bu daha basittir:

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

Verim

Performanslardaki fark, ipin uzunluğu ile büyük ölçüde artar. jsperf , 10 uzunluğundaki dizeler için ikinci çözümün (bölme ve birleştirme) önceki çözümden (dilim kullanarak) iki kat daha yavaş olduğunu, 100 harflik dizeler için x5 olduğunu ve 1000 harfli dizeler için x50 olduğunu Ops / saniye:

                      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

10 harften 100 harfe geçerken 1. ve 2. argümanları değiştirdiğime dikkat edin (yine de 100 harf için yapılan testin 10 harf için olandan daha hızlı çalışmasına şaşırıyorum).


2

String için sadece substr kullanın

ör.

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

Sonuç = ello dünyası!


1

Yani, bir String prototipine splice yöntemi ekleyen her ne olursa olsun, spec için şeffaf olarak çalışamaz ...

Birini uzatalım:

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;
}
  • Ekleme stilinde her 3 bağımsız değişken grubu "ekleme".
  • Eğer birden fazla 3 bağımsız grup varsa özeldir, her kesimin sonu bir sonrakinin başlangıcı olacaktır.
    • '0123456789'. Ekleme (4,1, 'dördüncü', 8,1, 'sekizinci'); // '0123fourth567eighth9' döndür
  • Her gruptaki ("eklenecek hiçbir şey" olarak kabul edilmeyen) son argümanı bırakabilir veya sıfırlayabilirsiniz.
    • '0123456789'. Ekleme (-4,2); // '0123459' döndür
  • Son gruptaki 1. bağımsız değişken hariç tümünü kaldırabilirsiniz ("1. bağımsız değişken konumundan sonra tümünü kes" olarak kabul edilir)
    • '0123456789'.splice (0,2, null, 3,1, null, 5,2,' / ', 8); // '24 / 7'yi döndür
  • Birden fazla geçerseniz, soldan sağa sırasını kendi kendinize kontrol etmeniz GEREKİR!
  • Ve eğer istemiyorsanız, bunu şu şekilde KULLANMAMALISINIZ:
    • '0123456789'.splice (4, -3,' ne? '); // "0123what? 123456789" döndür

0

Louis'in cevabının Stringprototip işlevi olarak yöntemi :

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

Misal:

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

0

Ekleme değeri 0 veya diğer yanlış değerler olduğunda Louis'in spliceSlice yöntemi başarısız oluyor, işte bir düzeltme:

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

Sorunumu bu kodu kullanarak çözdüm, eksik eklemenin yerini alıyorum.

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 
}

Belirli bir kelimeden önce / sonra bir karakteri silmem gerekiyordu, konumu aldıktan sonra dize ikiye bölündü ve ardından bir ofset kullanarak karakterleri esnek bir şekilde kaldırarak yeniden oluşturuldu. pos

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.