Có phương pháp nối nào cho chuỗi không?


87

Javascript splicechỉ hoạt động với các mảng. Có phương pháp tương tự cho chuỗi không? Hay tôi nên tạo chức năng tùy chỉnh của riêng mình?

Các phương thức substr()substring()sẽ chỉ trả về chuỗi đã trích xuất và không sửa đổi chuỗi ban đầu. Những gì tôi muốn làm là loại bỏ một số phần khỏi chuỗi của tôi và áp dụng thay đổi cho chuỗi ban đầu. Hơn nữa, phương thức replace()sẽ không hoạt động trong trường hợp của tôi vì tôi muốn xóa các phần bắt đầu từ một chỉ mục và kết thúc ở một số chỉ mục khác, chính xác như những gì tôi có thể làm với splice()phương thức. Tôi đã thử chuyển đổi chuỗi của mình thành một mảng, nhưng đây không phải là một phương pháp gọn gàng.


str.splitcó thể là chức năng bạn đang tìm kiếm: google.com/#q=javascript+string+split
Anderson Xanh

1
Có gì sai với str = str.slice()?
elclanrs

1
Có vẻ như một vấn đề XY, chính xác là bạn đang cố gắng làm gì? Chuỗi không được truyền bằng tham chiếu, không giống như mảng và đối tượng, vì vậy bạn không thay đổi chuỗi, bạn tạo chuỗi mới hoặc gán lại chuỗi mới cho chuỗi cũ.
elclanrs


6
return string.slice(0, startToSplice) + string.slice(endToSplice);, không?
raina77ow

Câu trả lời:


88

Nhanh hơn để cắt chuỗi hai lần, như thế này:

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

hơn là sử dụng một phép tách theo sau bởi một phép nối (phương pháp của Kumar Harsh), như thế này:

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

Đây là một jsperf so sánh hai phương pháp này và một vài phương thức khác. (jsperf đã ngừng hoạt động vài tháng nay. Vui lòng đề xuất các lựa chọn thay thế trong phần nhận xét.)

Mặc dù đoạn mã trên triển khai các hàm tái tạo chức năng chung của nó splice, nhưng việc tối ưu hóa mã cho trường hợp được trình bày bởi người hỏi (nghĩa là không thêm gì vào chuỗi đã sửa đổi) không thay đổi hiệu suất tương đối của các phương thức khác nhau.


3
Bạn có thể thêm điều này trên toàn cầu với: String.prototype.splice = function (index, count, add) { return this.slice(0, index) + (add || "") + this.slice(index + count); } Chỉ cần lưu ý rằng nó không hoạt động hoàn toàn giống như phương thức nối mảng vì các chuỗi là bất biến (bạn không thể sửa đổi chúng sau khi được tạo). Vì vậy, cách sử dụng sẽ giống như:var s="ss"; s = s.splice(0,1,"t");
William Neely.

@WilliamNeely: var StringUtils={'StringSplice':/*func def*/};sẽ là tiêu chuẩn cho thao tác chuỗi như bạn đã nói rằng nó là bất biến.
Ông Polywhirl

spliceSlice và spliceSplit không bình đẳng về mặt chức năng do Array.prototype.splice chấp nhận các chỉ số âm: jsfiddle.net/sykteho6/5 .
Martijn

1
@Mzialla Cảm ơn, tôi đã thêm mã để xử lý nó.
Louis

Tạo các giao diện tạm thời và giới thiệu các vị trí cho các lỗi từng lỗi một, chưa kể đến mã mất nhiều thời gian hơn để con người xử lý thay vì phân tách (""). Splice (...). Join ("") là sự đánh đổi đáng được xem xét. Vấn đề tốc độ chỉ là một vấn đề nếu nó là một vấn đề.
Ben Fletcher

15

Biên tập

Tất nhiên đây không phải là cách tốt nhất để "nối" một chuỗi, tôi đã đưa ra điều này làm ví dụ về cách triển khai sẽ như thế nào, điều này là thiếu sót và rất rõ ràng từ một split (), splice () và join (). Để triển khai tốt hơn nhiều, hãy xem phương pháp của Louis .


Không, không có cái gọi là a String.splice, nhưng bạn có thể thử điều này:

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

Tôi nhận ra rằng không có splicechức năng nào như trong Mảng, vì vậy bạn phải chuyển đổi chuỗi thành một mảng. Không may...


trong trường hợp của tôi, tôi đang làm việc trên một chuỗi động vì vậy tôi cần chỉ định các chỉ số chứ không phải giá trị ký tự.
ProllyGeek

Vâng, điều đó thật không may là chính xác. Nhưng bạn có thể nhận được các chỉ số của nhân vật bằng cách sử dụng String.prototype.indexOf như"asdsd".indexOf('s');
kumarharsh

3
Thay vì sử dụng str.split, bạn có thể sử dụng cú pháp lây lan ES6 như vậy:[...str]
Robbie

5

Đây là một cuốn sách nhỏ xinh xắn của Curry giúp dễ đọc hơn (IMHO):

Chữ ký của hàm thứ hai giống với Array.prototype.splicephương thức.

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

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

Tôi biết đã có một câu trả lời được chấp nhận, nhưng hy vọng điều này hữu ích.


1
Np. Bạn thậm chí có thể trừu tượng hóa điều này để cho phép, ví dụ, một 'method'tham số tùy chọn để bạn có thể chuyển vào Array.prototype[method]và coi các chuỗi hoàn toàn giống như mảng. Ngoài ra, với một mình thế này, bạn có thể trừu tượng quá trình thực tế để chức năng khác - và nếu không có chuỗi, trả về một hàm mà sẽ lấy chuỗi và đảo ngược cà ri: mutate()(1, 1, '1')('101'); Thậm chí, bạn có thể gõ các đối số để loại bỏ câu lệnh gọi trống - thậm chí đóng gói chính một phương thức. Nếu bạn cần những thứ này, bạn có thể muốn xem xét Command Pattern . Chỉ cần nhổ bóng ở đây.
Cody

3

Tôi muốn đưa ra một giải pháp thay thế đơn giản hơn cho cả phương pháp Kumar / Cody và Louis. Trong tất cả các bài kiểm tra tôi đã chạy, nó hoạt động nhanh như phương pháp Louis (xem các bài kiểm tra khó để biết điểm chuẩn).

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

Bạn có thể sử dụng nó như thế này:

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

Xem Kết quả Kiểm tra: https://jsfiddle.net/0quz9q9m/5/


ít nhất bạn nên thực hiện `+ (insertString ||" ") +` thay vì `+ insertString + , otherwise the third argument is not optional. This implementation also doesn't take care of startIndex <0` không giống như các đề xuất khác. Great ví dụ của việc sử dụng, mặc dù
YakovL

3

Có vẻ như có rất nhiều sự nhầm lẫn chỉ được giải quyết trong các bình luận của elclanrs và raina77ow, vì vậy hãy để tôi đăng một câu trả lời làm rõ.

Làm rõ

Từ " string.splice" người ta có thể mong đợi rằng nó, giống như đối với mảng:

  • chấp nhận tối đa 3 đối số: vị trí bắt đầu, độ dài và (tùy chọn) chèn (chuỗi)
  • trả lại phần bị cắt
  • sửa đổi chuỗi gốc

Vấn đề là, yêu cầu 3d không thể được thực hiện vì các chuỗi là bất biến (liên quan: 1 , 2 ), tôi đã tìm thấy nhận xét chuyên dụng nhất ở đây :

Trong JavaScript, chuỗi là kiểu giá trị nguyên thủy chứ không phải đối tượng ( spec ). Trong thực tế, tính đến ES5, họ là một trong những loại chỉ có 5 giá trị bên cạnh null, undefined, numberboolean. Strings được sự phân công của giá trịkhông bằng cách tham khảo và được thông qua như vậy. Vì vậy, các chuỗi không chỉ là bất biến, chúng còn là một giá trị . Thay đổi chuỗi "hello"thành "world"giống như việc quyết định từ nay số 3 là số 4 ... chẳng có ý nghĩa gì.

Vì vậy, với điều đó trong tài khoản, người ta có thể mong đợi điều " string.splice" chỉ:

  • chấp nhận tối đa 2 đối số: vị trí bắt đầu, độ dài (việc chèn không có ý nghĩa gì vì chuỗi không bị thay đổi)
  • trả lại phần bị cắt

đó là cái gì substr; Hay cách khác,

  • chấp nhận tối đa 3 đối số: vị trí bắt đầu, độ dài và (tùy chọn) chèn (chuỗi)
  • trả về chuỗi đã sửa đổi (không có phần cắt và có chèn)

đó là chủ đề của phần tiếp theo.

Các giải pháp

Nếu bạn quan tâm đến việc tối ưu hóa, bạn có thể nên sử dụng triển khai của 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);
}

Tuy nhiên, việc điều trị chỉ số ngoài ranh giới có thể khác nhau. Tùy thuộc vào nhu cầu của bạn, bạn có thể muốn:

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

hoặc thậm chí

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

Nếu bạn không quan tâm đến hiệu suất, bạn có thể muốn điều chỉnh đề xuất của Kumar, dễ hiểu hơn:

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

Hiệu suất

Sự khác biệt về hiệu suất tăng lên đáng kể theo độ dài của dây. jsperf cho thấy rằng đối với các chuỗi có độ dài là 10, giải pháp thứ hai (tách và nối) chậm hơn hai lần so với giải pháp trước đây (sử dụng lát cắt), đối với chuỗi 100 ký tự là x5 và đối với chuỗi 1000 ký tự là x50, tính bằng Ops / giây là:

                      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

lưu ý rằng tôi đã thay đổi đối số 1 và 2 khi chuyển từ 10 chữ cái sang 100 chữ cái (tôi vẫn ngạc nhiên khi bài kiểm tra 100 chữ cái chạy nhanh hơn bài kiểm tra 10 chữ cái).


2

Chỉ cần sử dụng substr cho chuỗi

Ví dụ.

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

Kết quả = ello world!


1

Vì vậy, bất cứ điều gì thêm phương thức nối vào một nguyên mẫu chuỗi đều không thể hoạt động minh bạch đối với đặc điểm kỹ thuật ...

Hãy làm một số mở rộng nó:

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;
}
  • Mỗi nhóm 3 args "chèn" theo kiểu mối nối.
  • Đặc biệt nếu có nhiều hơn một nhóm 3 args, kết thúc của mỗi lần cắt sẽ là bắt đầu của tiếp theo.
    • '0123456789'.splice (4,1,' thứ tư ', 8,1,' thứ tám '); // trả về '0123fourth567eighth9'
  • Bạn có thể bỏ hoặc không đối số cuối cùng trong mỗi nhóm (được coi là "không có gì để chèn")
    • '0123456789'.splice (-4,2); // trả về '0123459'
  • Bạn có thể loại bỏ tất cả trừ đối số thứ nhất trong nhóm cuối cùng (được coi là "cắt tất cả sau vị trí đối số thứ nhất")
    • '0123456789'.splice (0,2, null, 3,1, null, 5,2,' / ', 8); // trả về '24/7 '
  • nếu bạn vượt qua nhiều lần, bạn PHẢI tự mình kiểm tra loại vị trí từ trái sang phải!
  • Và nếu bạn không muốn, bạn KHÔNG PHẢI sử dụng nó như thế này:
    • '0123456789'.splice (4, -3,' cái gì? '); // trả về "0123 what? 123456789"

0

Câu trả lời của phương pháp Louis , như một Stringhàm nguyên mẫu:

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

Thí dụ:

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

0

Phương thức spliceSlice của Louis không thành công khi giá trị thêm là 0 hoặc các giá trị sai khác, đây là cách khắc phục:

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

Tôi đã giải quyết vấn đề của mình bằng cách sử dụng mã này, là một sự thay thế phần nào cho mối nối bị thiếu.

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 
}

Tôi cần xóa một ký tự trước / sau một từ nhất định, sau khi bạn nhận được vị trí, chuỗi được chia làm hai và sau đó sắp xếp lại bằng cách linh hoạt loại bỏ các ký tự bằng cách sử dụng một khoảng lệch dọc pos

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.