Tạo một chuỗi có độ dài thay đổi, chứa đầy một ký tự lặp lại


164

Vì vậy, câu hỏi của tôi đã được người khác hỏi ở dạng Java ở đây: Java - Tạo một cá thể Chuỗi mới với độ dài được chỉ định và chứa đầy ký tự cụ thể. Giải pháp tốt nhất?

. . . nhưng tôi đang tìm kiếm JavaScript tương đương.

Về cơ bản, tôi muốn tự động điền vào các trường văn bản với các ký tự "#", dựa trên thuộc tính "maxlength" của từng trường. Vì vậy, nếu một đầu vào có maxlength="3", thì trường sẽ được điền "###".

Lý tưởng nhất là sẽ có một cái gì đó giống như Java StringUtils.repeat("#", 10);, nhưng, cho đến nay, tùy chọn tốt nhất mà tôi có thể nghĩ đến là lặp qua và nối các ký tự "#", mỗi lần một, cho đến khi đạt được độ dài tối đa. Tôi không thể lay chuyển được cảm giác rằng có một cách hiệu quả hơn để làm điều đó hơn thế.

Có ý kiến ​​gì không?

FYI - Tôi không thể đơn giản đặt giá trị mặc định trong đầu vào, bởi vì các ký tự "#" cần xóa tiêu điểm và, nếu người dùng không nhập giá trị, sẽ cần phải "nạp lại" khi bị mờ. Đó là bước "nạp tiền" mà tôi quan tâm


1
Bạn đang làm điều này để che dấu văn bản của một trường đầu vào?
Xoài Feisty

@MatthewCox: Không, sẽ cung cấp thêm màn hình hiển thị hình ảnh tối đa. Trong trường hợp này, nó dành cho một tập hợp các trường số điện thoại được chia thành 3 phần của số. Nó sẽ chỉ ra rằng 2 trường đầu tiên cần 3 chữ số và các nhu cầu cuối cùng 4.
Talemyn

Câu trả lời:


302

Cách tốt nhất để làm điều này (mà tôi đã thấy) là

var str = new Array(len + 1).join( character );

Điều đó tạo ra một mảng với độ dài cho trước, và sau đó nối nó với chuỗi đã cho để lặp lại. Các .join()chức năng tôn độ dài mảng bất kể các yếu tố có giá trị được giao, và các giá trị không xác định được trả lại như chuỗi rỗng.

Bạn phải thêm 1 vào độ dài mong muốn vì chuỗi phân tách đi giữa các thành phần mảng.


Đóng đinh nó :) Tôi chỉ cần nhớ sử dụng parseInt()trên giá trị maxlength đầu vào trước khi sử dụng nó để kích thước mảng. Chỉ cần những gì tôi đang tìm kiếm . . . cảm ơn!
Talemyn

11
Lưu ý, giải pháp này RẤT chậm. Nó trông gợi cảm nhưng có lẽ chính xác là cách sai để làm điều này.
Hogan

23
repeatchức năng mới được tích hợp trong String.prototype xử lý việc này ngay bây giờ (ES6 +)
AlexMA

Giải pháp ốm đau. Cảm ơn cho nó!
C4d

156

Hãy thử xem: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Chắc chắn là cách thực hiện dễ dàng nhất, nhưng cũng ít được hỗ trợ nhất, vì đó là một phần của ECMAScript 6. Có vẻ như, ngay bây giờ, nó chỉ được hỗ trợ trong Firefox, Chrome và phiên bản Safari của máy tính để bàn.
Talemyn

5
Nếu bạn không phiền khi sử dụng lodash , bạn có thể sử dụng như sau: _.repeat('*',10);
Geraud Gratacap 5/2/2016

4
Bây giờ là năm 2018 và ES6 đã được thiết lập tốt - đây sẽ là câu trả lời được chấp nhận. Và trong trường hợp cần hỗ trợ các trình duyệt cũ cho những người không sử dụng Babel hoặc một cái gì đó tương tự, bạn có thể sử dụng lodash như đã đề cập ở trên hoặc polyfill để sao lưu.
seanTcoyote

@seanTcoyote Nhiều như tôi muốn, vẫn có những người phải tranh luận với IE 11 và Adroid's Webview, cả hai đều không hỗ trợ repeat()phương pháp này. Mong đến ngày tôi không phải quan tâm đến họ nữa. . .
Talemyn

Thật không may, không tương thích với IE
Lorenzo L Cả

30

Thật không may, mặc dù cách tiếp cận Array.join được đề cập ở đây rất ngắn gọn, nhưng nó chậm hơn khoảng 10 lần so với cách triển khai dựa trên chuỗi nối. Nó thực hiện đặc biệt xấu trên các chuỗi lớn. Xem bên dưới để biết chi tiết hiệu suất đầy đủ.

Trên Firefox, Chrome, Node.js MacOS, Node.js Ubuntu và Safari, cách triển khai nhanh nhất tôi đã thử nghiệm là:

function repeatChar(count, ch) {
    if (count == 0) {
        return "";
    }
    var count2 = count / 2;
    var result = ch;

    // double the input until it is long enough.
    while (result.length <= count2) {
        result += result;
    }
    // use substring to hit the precise length target without
    // using extra memory
    return result + result.substring(0, count - result.length);
};

Đây là dài dòng, vì vậy nếu bạn muốn thực hiện ngắn gọn, bạn có thể đi với cách tiếp cận ngây thơ; nó vẫn thực hiện betweeb 2X đến 10X tốt hơn so với cách tiếp cận Array.join và cũng nhanh hơn so với triển khai nhân đôi cho các đầu vào nhỏ. Mã số:

// naive approach: simply add the letters one by one
function repeatChar(count, ch) {
    var txt = "";
    for (var i = 0; i < count; i++) {
        txt += ch;
    }
    return txt;
}

Thêm thông tin:


1
Giải pháp này vẫn chậm hơn (từ 2 đến 3 bậc độ lớn) so với giải pháp của tôi.
Hogan

@Hogan Giải pháp của bạn không tạo ra một chuỗi đầy từ đâu cả. Bạn tự tạo và sau đó chỉ cần trích xuất một chuỗi con.
StanE

Cách tiếp cận này chậm hơn 10 lần so với Array.join trong Node.js cho các chuỗi cực lớn.
Anshul Koka

21

Tôi sẽ tạo một chuỗi không đổi và sau đó gọi chuỗi con trên đó.

Cái gì đó như

var hashStore = '########################################';

var Fiveup = hashStore.substring(0,5);

var Tenup = hashStore.substring(0,10);

Nhanh hơn một chút.

http://jsperf.com/const-vs-join


1
Điều này rất thông minh! Và nó thậm chí hoạt động với các mẫu chuỗi chứa nhiều ký tự.
Markus

1
Chỉ cần xem lại trang này vì nó dường như tiếp tục nhận được nhiều sự chú ý và muốn bình luận về giải pháp của bạn. Mặc dù tôi chắc chắn thích sự đơn giản và tốc độ trong cách tiếp cận của bạn, mối quan tâm lớn nhất của tôi với nó là xung quanh việc bảo trì / tái sử dụng. Mặc dù trong kịch bản cụ thể của tôi, tôi không cần nhiều hơn 4 ký tự, như một hàm chung, sử dụng chuỗi có độ dài cố định có nghĩa là bạn phải quay lại và cập nhật chuỗi, nếu trường hợp sử dụng của bạn cần thêm ký tự. Hai giải pháp khác cho phép linh hoạt hơn trong vấn đề đó. +1 cho tốc độ, mặc dù.
Talemyn

1
Ồ, và, mặt trái (và tôi nhận ra rằng đây thực sự là một mối quan tâm về phong cách, hơn là một chương trình), duy trì chuỗi 30 ký tự sẽ chỉ được sử dụng cho 3-4 ký tự không phù hợp với tôi cũng vậy . . . một lần nữa, một vấn đề nhỏ xung quanh tính linh hoạt của giải pháp cho các trường hợp sử dụng khác nhau.
Talemyn

@talemyn Trong CNTT mọi thứ đều là sự đánh đổi. Có chuỗi 4 ký tự và làm cho nó lớn hơn hoặc có chuỗi 30 ký tự và không phải lo lắng. Nói chung, một chuỗi không đổi có kích thước bất kỳ - thậm chí 1k, là việc sử dụng tài nguyên nhỏ trên các máy hiện đại.
Hogan

@Hogan - Hoàn toàn đồng ý. . . và, đó thực sự là một phần lý do khiến tôi không chú trọng nhiều vào tốc độ. Trong trường hợp sử dụng cụ thể của tôi, tôi đã tìm kiếm ba chuỗi có độ dài 3, 3 và 4 ký tự. Mặc dù giải pháp của Pointy là chậm nhất, vì dây ngắn và chỉ có một vài trong số chúng, tôi đã đi với anh ấy vì tôi thích thực tế là nó được sắp xếp hợp lý, dễ đọc và dễ bảo trì. Cuối cùng, tất cả chúng đều là giải pháp tốt cho các biến thể khác nhau của câu hỏi. . . tất cả sẽ phụ thuộc vào mức độ ưu tiên của tình huống cụ thể của bạn.
Talemyn


5

Một tùy chọn ES6 tuyệt vời sẽ là padStartmột chuỗi trống. Như thế này:

var str = ''.padStart(10, "#");

Lưu ý: điều này sẽ không hoạt động trong IE (không có polyfill).


3
Bất kỳ lý do cụ thể nào mà bạn muốn giới thiệu cách tiếp cận ES6 này so với s = '#'.repeat(10)câu trả lời khác ( ) từ câu trả lời của @ user4227915 ở trên?
Talemyn

@talemyn Cú pháp đơn giản
Mendy

3

Phiên bản hoạt động trong tất cả các trình duyệt

Hàm này thực hiện những gì bạn muốn và thực hiện nhanh hơn rất nhiều so với tùy chọn được đề xuất trong câu trả lời được chấp nhận:

var repeat = function(str, count) {
    var array = [];
    for(var i = 0; i <= count;)
        array[i++] = str;
    return array.join('');
}

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

var repeatedCharacter = repeat("a", 10);

Để so sánh hiệu suất của chức năng này với tùy chọn được đề xuất trong câu trả lời được chấp nhận, hãy xem FiddleFiddle này để biết điểm chuẩn.

Phiên bản chỉ dành cho trình duyệt hiện đại

Trong các trình duyệt hiện đại, bây giờ bạn cũng có thể làm điều này:

var repeatedCharacter = "a".repeat(10) };

Tùy chọn này thậm chí còn nhanh hơn. Tuy nhiên, thật không may, nó không hoạt động trong bất kỳ phiên bản Internet explorer nào.

Các số trong bảng chỉ định phiên bản trình duyệt đầu tiên hỗ trợ đầy đủ phương thức:

nhập mô tả hình ảnh ở đây


3
For Evergreen browsers, this will build a staircase based on an incoming character and the number of stairs to build.
function StairCase(character, input) {
    let i = 0;
    while (i < input) {
        const spaces = " ".repeat(input - (i+1));
        const hashes = character.repeat(i + 1);
        console.log(spaces + hashes);
        i++;
    }
}

//Implement
//Refresh the console
console.clear();
StairCase("#",6);   

Bạn cũng có thể thêm một polyfill cho Lặp lại cho các trình duyệt cũ hơn

    if (!String.prototype.repeat) {
      String.prototype.repeat = function(count) {
        'use strict';
        if (this == null) {
          throw new TypeError('can\'t convert ' + this + ' to object');
        }
        var str = '' + this;
        count = +count;
        if (count != count) {
          count = 0;
        }
        if (count < 0) {
          throw new RangeError('repeat count must be non-negative');
        }
        if (count == Infinity) {
          throw new RangeError('repeat count must be less than infinity');
        }
        count = Math.floor(count);
        if (str.length == 0 || count == 0) {
          return '';
        }
        // Ensuring count is a 31-bit integer allows us to heavily optimize the
        // main part. But anyway, most current (August 2014) browsers can't handle
        // strings 1 << 28 chars or longer, so:
        if (str.length * count >= 1 << 28) {
          throw new RangeError('repeat count must not overflow maximum string size');
        }
        var rpt = '';
        for (;;) {
          if ((count & 1) == 1) {
            rpt += str;
          }
          count >>>= 1;
          if (count == 0) {
            break;
          }
          str += str;
        }
        // Could we try:
        // return Array(count + 1).join(this);
        return rpt;
      }
    } 

2

Dựa trên câu trả lời từ Hogan và Zero Trick Pony. Tôi nghĩ rằng điều này nên vừa đủ nhanh và linh hoạt để xử lý tốt hầu hết các trường hợp sử dụng:

var hash = '####################################################################'

function build_string(length) {  
    if (length == 0) {  
        return ''  
    } else if (hash.length <= length) {  
        return hash.substring(0, length)  
    } else {  
        var result = hash  
        const half_length = length / 2  
        while (result.length <= half_length) {  
            result += result  
        }  
        return result + result.substring(0, length - result.length)  
    }  
}  

Vui lòng thêm một số giải thích cho câu trả lời của bạn vì đoạn mã tự nó không cung cấp câu trả lời.
Clijsters

@Leandro Thông minh và giảm thiểu xử lý! +1
LMSingh

Tôi nghĩ bạn có nghĩa là hash.length> = length
cipak

1

Bạn có thể sử dụng dòng đầu tiên của hàm dưới dạng một lớp lót nếu bạn muốn:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
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.