Buat string dengan panjang variabel, diisi dengan karakter yang berulang

164

Jadi, pertanyaan saya telah ditanyakan oleh orang lain dalam bentuk Java di sini: Java - Buat instance String baru dengan panjang yang ditentukan dan diisi dengan karakter tertentu. Solusi terbaik?

. . . tapi saya sedang mencari yang setara JavaScript.

Pada dasarnya, saya ingin mengisi bidang teks secara dinamis dengan karakter "#", berdasarkan pada atribut "maxlength" dari masing-masing bidang. Jadi, jika suatu input memiliki maxlength="3", maka isian akan diisi dengan "###".

Idealnya akan ada sesuatu seperti Java StringUtils.repeat("#", 10);, tetapi, sejauh ini, opsi terbaik yang dapat saya pikirkan adalah untuk mengulang dan menambahkan karakter "#", satu per satu, hingga panjang maksimal tercapai. Saya tidak bisa menghilangkan perasaan bahwa ada cara yang lebih efisien untuk melakukannya daripada itu.

Ada ide?

FYI - Saya tidak bisa begitu saja menetapkan nilai default di input, karena karakter "#" perlu jelas pada fokus, dan, jika pengguna tidak memasukkan nilai, harus "diisi" pada blur. Ini langkah "isi ulang" yang saya khawatirkan

talemyn
sumber
1
Apakah Anda melakukan ini untuk menutupi teks bidang input?
Feisty Mango
@ MatthewCox: Tidak, itu lebih untuk memberikan tampilan visual maxlength. Dalam hal ini, itu untuk satu set bidang nomor telepon yang dibagi menjadi 3 bagian dari nomor tersebut. Ini akan menunjukkan bahwa 2 bidang pertama membutuhkan 3 digit dan kebutuhan terakhir 4.
talemyn
kemungkinan duplikat Ulangi String - Javascript
Felix Kling

Jawaban:

302

Cara terbaik untuk melakukan ini (yang pernah saya lihat) adalah

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

Itu menciptakan array dengan panjang yang diberikan, dan kemudian bergabung dengan string yang diberikan untuk diulang. The .join()Fungsi menghormati panjang array terlepas dari apakah elemen memiliki nilai yang ditetapkan, dan nilai-nilai terdefinisi tersebut diberikan sebagai string kosong.

Anda harus menambahkan 1 ke panjang yang diinginkan karena string pemisah berada di antara elemen array.

Runcing
sumber
Berhasil. :) Saya hanya perlu ingat untuk menggunakan parseInt()nilai input maxlength sebelum menggunakannya untuk ukuran array. Apa yang saya cari. . . Terima kasih!
talemyn
11
Catatan, solusi ini SANGAT lambat. Ini terlihat seksi tetapi mungkin cara yang salah untuk melakukan ini.
Hogan
23
repeatfungsi baru yang dibangun ke dalam String.prototype menangani ini sekarang (ES6 +)
AlexMA
Solusi sakit. Terimakasih untuk ini!
C4d
156

Coba ini: P

s = '#'.repeat(10)

document.body.innerHTML = s


sumber
4
Jelas implementasi termudah, tetapi juga yang paling tidak didukung, karena itu bagian dari ECMAScript 6. Sepertinya, saat ini, itu hanya didukung di Firefox, Chrome, dan versi desktop Safari.
talemyn
5
Jika Anda tidak keberatan menggunakan lodash , Anda dapat menggunakan yang berikut: _.repeat('*',10);
Geraud Gratacap
4
Sekarang tahun 2018 dan ES6 sudah mapan - ini harus menjadi jawaban yang diterima. Dan jika perlu untuk mendukung browser lawas bagi mereka yang tidak menggunakan Babel atau yang serupa, Anda dapat menggunakan lodash seperti yang disebutkan di atas, atau polyfill untuk cadangan.
seanTcoyote
@ seanTcoyote Seperti yang saya inginkan, masih ada orang yang harus bersaing dengan IE 11 dan Tampilan Web Adroid, yang keduanya tidak mendukung repeat()metode ini. Menantikan hari ketika saya tidak perlu peduli lagi dengan mereka, saya sendiri. . .
talemyn
Sayangnya, tidak kompatibel dengan IE
Lorenzo Lerate
30

Sayangnya meskipun pendekatan Array.join yang disebutkan di sini singkat, ini sekitar 10X lebih lambat daripada implementasi berbasis string-concatenation. Ini melakukan sangat buruk pada string besar. Lihat di bawah untuk detail kinerja lengkap.

Di Firefox, Chrome, Node.js MacOS, Node.js Ubuntu, dan Safari, implementasi tercepat yang saya uji adalah:

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

Ini verbose, jadi jika Anda menginginkan implementasi singkat Anda bisa menggunakan pendekatan naif; itu masih melakukan antara 2X hingga 10X lebih baik daripada pendekatan Array.join, dan juga lebih cepat daripada implementasi penggandaan untuk input kecil. Kode:

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

Informasi lebih lanjut:

Zero Trick Pony
sumber
1
Ini masih BANYAK lebih lambat (dengan 2 hingga 3 kali lipat) dari solusi saya.
Hogan
@Hogan Solusi Anda tidak membuat string yang diisi entah dari mana. Anda membuatnya sendiri lalu mengekstraksi substring.
StanE
Pendekatan ini 10x lebih lambat dari Array.join di Node.js untuk string yang sangat besar.
Anshul Koka
21

Saya akan membuat string konstan dan kemudian memanggil substring di atasnya.

Sesuatu seperti

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

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

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

Sedikit lebih cepat juga.

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

Hogan
sumber
1
Ini sangat pintar! Dan itu bahkan bekerja dengan pola string yang berisi banyak karakter.
Markus
1
Kunjungi kembali halaman ini karena sepertinya terus mendapatkan banyak perhatian dan ingin mengomentari solusi Anda. Meskipun saya sangat menyukai kesederhanaan dan kecepatan pendekatan Anda, perhatian terbesar saya adalah tentang pemeliharaan / penggunaan kembali. Sementara dalam skenario spesifik saya, saya tidak membutuhkan lebih dari 4 karakter, sebagai fungsi umum, menggunakan string panjang tetap berarti Anda harus kembali dan memperbarui string, jika use case Anda membutuhkan lebih banyak karakter. Dua solusi lainnya memungkinkan lebih banyak fleksibilitas dalam hal itu. +1 untuk kecepatan.
talemyn
1
Oh, dan, di sisi lain (dan saya menyadari ini benar-benar lebih dari masalah gaya, daripada yang terprogram), mempertahankan string karakter 30+ yang hanya akan digunakan untuk 3-4 karakter tidak cocok dengan yang lain. begitu juga dengan saya . . . sekali lagi, masalah kecil seputar fleksibilitas solusi untuk berbagai kasus penggunaan.
talemyn
@talemyn Dalam IT, semuanya merupakan trade off. Memiliki string 4 karakter dan membuatnya lebih besar atau memiliki string 30 karakter dan tidak khawatir. Semua dalam semua, string konstan ukuran apa pun - bahkan 1k, adalah penggunaan sumber daya kecil pada mesin modern.
Hogan
@Hogan - sepenuhnya setuju. . . dan, itu sebenarnya bagian dari alasan saya tidak terlalu menekankan pada kecepatan. Dalam kasus penggunaan khusus saya, saya mencari tiga string yang panjangnya 3, 3, dan 4 karakter. Sementara solusi Pointy paling lambat, karena senarnya pendek dan hanya ada sedikit, saya ikut dengannya karena saya menyukai fakta bahwa itu efisien, mudah dibaca, dan mudah dipelihara. Pada akhirnya, mereka semua adalah solusi yang baik untuk variasi pertanyaan yang berbeda. . . itu semua akan tergantung pada apa prioritas untuk situasi spesifik Anda.
talemyn
5

Opsi ES6 yang bagus padStartadalah string kosong. Seperti ini:

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

Catatan: ini tidak akan berfungsi di IE (tanpa polyfill).

Mendy
sumber
3
Adakah alasan khusus bahwa Anda akan merekomendasikan pendekatan ES6 ini di atas yang lain ( s = '#'.repeat(10)) dari jawaban @ user4227915 di atas?
talemyn
@talemyn Sintaks simpler
Mendy
3

Versi yang berfungsi di semua browser

Fungsi ini melakukan apa yang Anda inginkan, dan melakukan jauh lebih cepat daripada opsi yang disarankan dalam jawaban yang diterima:

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

Anda menggunakannya seperti ini:

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

Untuk membandingkan kinerja fungsi ini dengan opsi yang diusulkan dalam jawaban yang diterima, lihat Fiddle dan Fiddle ini untuk tolok ukur.

Versi hanya untuk browser modern

Di browser modern, sekarang Anda juga dapat melakukan ini:

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

Opsi ini bahkan lebih cepat. Namun, sayangnya itu tidak berfungsi di versi Internet Explorer apa pun.

Angka-angka dalam tabel menentukan versi browser pertama yang sepenuhnya mendukung metode ini:

masukkan deskripsi gambar di sini

John Slegers
sumber
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);   

Anda juga dapat menambahkan polyfill untuk Ulangi untuk browser yang lebih lama

    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;
      }
    } 
Terry Slack
sumber
2

Berdasarkan jawaban dari Hogan dan Zero Trick Pony. Saya pikir ini harus cepat dan cukup fleksibel untuk menangani sebagian besar kasus penggunaan dengan baik:

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)  
    }  
}  
Leandro
sumber
Harap tambahkan beberapa penjelasan lagi untuk jawaban Anda karena cuplikan kode itu sendiri tidak memberikan jawaban.
Clijsters
@Leandro Pintar dan meminimalkan pemrosesan! +1
LMSingh
Saya pikir maksud Anda hash.length> = length
cipak
1

Anda dapat menggunakan baris pertama dari fungsi sebagai satu-baris jika Anda suka:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
Sarsaparilla
sumber