【问题标题】:Is there a splice method for strings?字符串有拼接方法吗?
【发布时间】:2013-12-28 18:00:33
【问题描述】:

Javascript splice 仅适用于数组。字符串有类似的方法吗?还是应该创建自己的自定义函数?

substr()substring() 方法只会返回提取的字符串,不会修改原始字符串。我想要做的是从我的字符串中删除一些部分并将更改应用于原始字符串。此外,replace() 方法在我的情况下不起作用,因为我想删除从索引开始并以其他索引结束的部分,就像我可以使用 splice() 方法一样。我尝试将我的字符串转换为数组,但这不是一个简洁的方法。

【问题讨论】:

  • str.split 可能是您正在寻找的功能:google.com/#q=javascript+string+split
  • str = str.slice() 有什么问题?
  • 看起来像一个 XY 问题,你到底想做什么?与数组和对象不同,字符串不是通过引用传递的,因此您不会改变字符串,而是创建新字符串或将新字符串重新分配给旧字符串。
  • return string.slice(0, startToSplice) + string.slice(endToSplice);,不是吗?

标签: javascript


【解决方案1】:

将字符串切片两次更快,如下所示:

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

而不是使用拆分后连接(Kumar Harsh 的方法),如下所示:

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

这是一个jsperf,它比较了这两种方法和其他几种方法。 (jsperf 已经停机几个月了。请在 cmets 中提出替代方案。)

尽管上面的代码实现了重现splice一般 功能的功能,但针对提问者提出的情况优化代码(即,不向修改后的字符串添加任何内容)并没有改变各种方法的相对性能。

【讨论】:

  • 您可以通过以下方式全局添加它: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*/}; 将是字符串操作的标准,正如您所说的那样,它是不可变的。
  • spliceSlice 和 spliceSplit 在功能上不相等,因为 Array.prototype.splice 接受负索引:jsfiddle.net/sykteho6/5
  • @Mzialla 谢谢,我已经添加了代码来处理它。
  • 创建临时变量并引入错误的位置,更不用说与 split("").splice(...).join 相比,人类处理时间更长的代码("") 是一个值得考虑的权衡。速度问题只有在成为问题时才是问题。
【解决方案2】:

编辑

这当然不是“拼接”字符串的最佳方式,我已将其作为实现方式的示例,这是有缺陷的,从 split()、splice() 和 join( )。如需更好的实现,请参阅Louis's 方法。


不,没有String.splice 这样的东西,但你可以试试这个:

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

我意识到数组中没有splice 函数,因此您必须将字符串转换为数组。运气不好...

【讨论】:

  • 在我的情况下,我正在处理动态字符串,所以我需要指定索引而不是字符值。
  • 是的,很遗憾这是正确的。但是你可以通过使用 String.prototype.indexOf as "asdsd".indexOf('s'); 来获取字符的索引
  • 不使用 str.split,您可以使用 ES6 扩展语法,如下所示:[...str]
  • 非常低效/慢/业余,你只需将之前和之后的部分连接起来就可以了!
【解决方案3】:

这是一个不错的小咖喱,它具有更好的可读性(恕我直言):

第二个函数的签名与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');

我知道已经有一个被接受的答案,但希望这是有用的。

【讨论】:

  • Np。您甚至可以将其抽象为允许使用可选的'method' 参数,这样您就可以传入Array.prototype[method] 并将字符串完全视为数组。此外,仅此一个,您可以将实际过程抽象为另一个函数——如果没有字符串,则返回一个函数,该函数将获取字符串并反转 curry:mutate()(1, 1, '1')('101');您甚至可以对参数进行duckType 以消除空调用的咖喱——甚至封装一个方法本身。如果您需要这些东西,您可能需要查看 Command Pattern。只是在这里吐痰。
  • 非常好的方法!
【解决方案4】:

elclanrs 和 raina77ow 似乎只在 cmets 中解决了很多困惑,所以让我发布一个澄清的答案。

澄清

来自“string.splice”的人可能会期待它,就像数组中的那个:

  • 最多接受 3 个参数:起始位置、长度和(可选)插入(字符串)
  • 退回剪切部分
  • 修改原字符串

问题是,由于字符串是不可变的(相关:12),无法满足 3d 要求,我找到了最专业的评论 here

在 JavaScript 中,字符串是原始值类型,不是对象 (spec)。事实上,在 ES5 中,它们是与 nullundefinednumberboolean 并列的仅有的 5 种值类型之一。字符串由 valuenot 通过引用分配,并按原样传递。因此,字符串不仅是不可变的,它们还是一个。将字符串 "hello" 更改为 "world" 就像决定从现在开始数字 3 就是数字 4……这没有任何意义。

因此,考虑到这一点,人们可能只期望“string.splice”这个东西:

  • 最多接受 2 个参数:起始位置、长度(插入没有意义,因为字符串没有改变)
  • 退回剪切部分

这就是substr 所做的;或者,或者,

  • 最多接受 3 个参数:起始位置、长度和(可选)插入(字符串)
  • 返回修改后的字符串(不带剪切部分,带插入)

这是下一节的主题。

解决方案

如果您关心优化,您可能应该使用 Mike 的实现:

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;

如果您不关心性能,您可能需要调整 Kumar 的建议,该建议更直接:

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

性能

随着琴弦长度的增加,性能上的差异会急剧增加。 jsperf shows,对于长度为 10 的字符串,后一种解决方案(拆分和连接)比前一种解决方案(使用切片)慢两倍,对于 100 个字母的字符串,它是 x5,对于 1000 个字母的字符串,它是 x50,在Ops/sec 它是:

                      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 个字母移动到 100 个字母时,我已经更改了 1st 和 2d 参数(但我仍然对 100 个字母的测试比 10 个字母的测试运行得更快感到惊讶)。

【讨论】:

    【解决方案5】:

    我想为 Kumar/Cody 和 Louis 方法提供一个更简单的替代方案。在我运行的所有测试中,它的执行速度与 Louis 方法一样快(请参阅基准测试小提琴测试)。

    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
    【解决方案6】:

    只需将 substr 用于字符串

    例如。

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

    结果 = 你好世界!

    【讨论】:

      【解决方案7】:

      方法Louis's 回答,作为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!"
      

      【讨论】:

        【解决方案8】:

        因此,无论向字符串原型添加拼接方法,都无法对规范透明...

        让我们做一些扩展它:

        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 个 args 组以拼接样式“插入”。
        • 特别是如果有超过一个 3 args 组,每个切割的结束将是下一个切割的开始。
          • '0123456789'.splice(4,1,'第四',8,1,'第八'); //返回'0123fourth567eighth9'
        • 您可以删除或归零每个组中的最后一个参数(被视为“无插入”)
          • '0123456789'.splice(-4,2); //返回'0123459'
        • 您可以删除最后一组中除第一个 arg 之外的所有内容(视为“在第一个 arg 位置之后全部剪切”)
          • '0123456789'.splice(0,2,null,3,1,null,5,2,'/',8); //返回'24/7'
        • 如果你通过多个,你必须自己检查位置从左到右的顺序!
        • 如果你不希望你一定不要这样使用它:
          • '0123456789'.splice(4,-3,'什么?'); //返回“0123what?123456789”

        【讨论】:

          【解决方案9】:

          Louis's spliceSlice 方法在 add 值为 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);
          }
          

          【讨论】:

            【解决方案10】:

            我使用此代码解决了我的问题,在某种程度上替代了缺少的接头。

            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 的偏移量灵活地删除字符来重新组合

            【讨论】:

              猜你喜欢
              • 2013-10-29
              • 1970-01-01
              • 1970-01-01
              • 2012-09-15
              • 1970-01-01
              • 2016-07-30
              • 1970-01-01
              • 2021-10-30
              • 2021-06-14
              相关资源
              最近更新 更多