Crea una stringa di lunghezza variabile, riempita con un carattere ripetuto


164

Quindi, la mia domanda è stata posta da qualcun altro nella sua forma Java qui: Java - Crea una nuova istanza String con lunghezza specificata e piena di carattere specifico. Soluzione migliore?

. . . ma sto cercando il suo equivalente JavaScript.

Fondamentalmente, voglio riempire dinamicamente i campi di testo con caratteri "#", in base all'attributo "lunghezza massima" di ciascun campo. Quindi, se un input ha maxlength="3", il campo verrebbe riempito con "###".

Idealmente ci sarebbe qualcosa come Java StringUtils.repeat("#", 10);, ma finora l'opzione migliore che mi viene in mente è quella di passare in rassegna e aggiungere i caratteri "#", uno alla volta, fino a raggiungere la lunghezza massima. Non riesco a scuotere la sensazione che ci sia un modo più efficiente per farlo.

Qualche idea?

Cordiali saluti - Non posso semplicemente impostare un valore predefinito nell'input, perché i caratteri "#" devono essere messi a fuoco e, se l'utente non ha inserito un valore, dovrà essere "riempito" in sfocatura. È il passo di "ricarica" ​​che mi interessa


1
Lo stai facendo per mascherare il testo di un campo di input?
Feisty Mango,

@MatthewCox: No, è più per fornire una visualizzazione visiva di massima lunghezza. In questo caso, è per un insieme di campi di numeri di telefono che sono divisi nelle 3 parti del numero. Mostrerebbe che i primi 2 campi hanno bisogno di 3 cifre e l'ultimo ha bisogno di 4.
talemyn

possibile duplicato di Repeat String - Javascript
Felix Kling

Risposte:


303

Il modo migliore per farlo (che ho visto) è

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

Ciò crea un array con la lunghezza data e quindi lo unisce con la stringa data da ripetere. La .join()funzione rispetta la lunghezza dell'array indipendentemente dal fatto che agli elementi siano assegnati valori e i valori indefiniti vengono visualizzati come stringhe vuote.

Devi aggiungere 1 alla lunghezza desiderata perché la stringa di separazione va tra gli elementi dell'array.


Azzeccato. :) Ho solo bisogno di ricordare di utilizzare parseInt()il valore di lunghezza massima degli ingressi prima di utilizzarlo per dimensionare l'array. Proprio quello che stavo cercando . . . Grazie!
talemyn,

11
Nota, questa soluzione è MOLTO lenta. Sembra sexy ma probabilmente è esattamente il modo sbagliato di farlo.
Hogan,

23
la nuova repeatfunzione integrata in String.prototype ora gestisce questa operazione (ES6 +)
AlexMA,

Soluzione malata. Grazie per questo!
C4d

156

Prova questo: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Sicuramente l'implementazione più semplice, ma anche la meno supportata, dal momento che fa parte di ECMAScript 6. Sembra che, al momento, sia supportata solo in Firefox, Chrome e versione desktop di Safari.
talemyn,

5
Se non ti dispiace usare lodash , potresti usare quanto segue: _.repeat('*',10);
Geraud Gratacap

4
È il 2018 e ES6 è ormai consolidato: questa dovrebbe essere la risposta accettata. E in caso di necessità di supportare browser legacy per coloro che non usano Babel o qualcosa di simile, puoi usare lodash come menzionato sopra o un polyfill per il backup.
seanTcoyote,

@seanTcoyote Per quanto mi piacerebbe, ci sono ancora persone che devono fare i conti con IE 11 e le visualizzazioni Web di Adroid, nessuna delle quali supporta il repeat()metodo. In attesa del giorno in cui non mi devo più preoccupare di loro, me stesso. . .
talemyn,

Sfortunatamente, non compatibile con IE
Lorenzo Lerate il

30

Sfortunatamente sebbene l'approccio Array.join menzionato qui sia conciso, è circa 10 volte più lento di un'implementazione basata sulla concatenazione di stringhe. Si comporta particolarmente male su corde di grandi dimensioni. Vedi sotto per i dettagli completi sulle prestazioni.

Su Firefox, Chrome, Node.js MacOS, Node.js Ubuntu e Safari, l'implementazione più veloce che ho provato è stata:

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

Questo è dettagliato, quindi se vuoi un'implementazione concisa potresti seguire un approccio ingenuo; esegue ancora tra 2X e 10X meglio dell'approccio Array.join ed è anche più veloce dell'implementazione doppia per input piccoli. Codice:

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

Ulteriori informazioni:


1
Questo è ancora MOLTO più lento (di 2-3 ordini di grandezza) rispetto alla mia soluzione.
Hogan,

@Hogan La tua soluzione non crea una stringa riempita dal nulla. Lo crei tu stesso e quindi estrai una sottostringa.
StanE

Questo approccio è 10 volte più lento di Array.join in Node.js per stringhe estremamente grandi.
Anshul Koka,

21

Vorrei creare una stringa costante e quindi chiamare sottostringa su di essa.

Qualcosa di simile a

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

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

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

Anche un po 'più veloce.

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


1
Questo è molto intelligente! E funziona anche con schemi di stringhe contenenti più caratteri.
Markus,

1
Stavo solo rivisitando questa pagina perché sembra continuare a ricevere molta attenzione e volevo commentare la tua soluzione. Sebbene mi piaccia sicuramente la semplicità e la velocità del tuo approccio, la mia più grande preoccupazione era la manutenzione / riutilizzo. Mentre nel mio scenario specifico, non avevo bisogno di più di 4 caratteri, come funzione generica, l'uso di una stringa di lunghezza fissa significa che devi tornare indietro e aggiornare la stringa, se il tuo caso d'uso ha bisogno di più caratteri. Le altre due soluzioni consentono una maggiore flessibilità in tal senso. +1 per la velocità, però.
talemyn,

1
Oh, e, dall'altro lato (e mi rendo conto che questo è davvero più di una preoccupazione stilistica, che a livello di programmazione), mantenere una stringa di oltre 30 caratteri che sarà usata sempre e solo per 3-4 caratteri non è stata adatta anche io . . . ancora una volta, un problema minore riguardo alla flessibilità della soluzione per vari casi d'uso.
talemyn,

@talemyn In IT tutto è un compromesso. Avere una stringa di 4 caratteri e renderla più grande o avere una stringa di 30 caratteri e non preoccuparti. Tutto sommato, una stringa costante di qualsiasi dimensione, anche 1k, è un utilizzo minuscolo delle risorse su macchine moderne.
Hogan

@Hogan - sono assolutamente d'accordo. . . e, in realtà, questo è uno dei motivi per cui non ho dato grande enfasi alla velocità. Nel mio caso d'uso specifico, stavo cercando tre stringhe lunghe 3, 3 e 4 caratteri. Mentre la soluzione di Pointy era la più lenta, poiché le stringhe erano corte e ce n'erano solo alcune, sono andata con la sua perché mi piaceva il fatto che fosse snella, facile da leggere e da mantenere. Alla fine, sono tutte buone soluzioni per diverse varianti della domanda. . . dipenderà tutto da quali sono le priorità per la tua situazione specifica.
talemyn,


5

Un'ottima opzione ES6 sarebbe quella di padStartuna stringa vuota. Come questo:

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

Nota: questo non funzionerà in IE (senza un polyfill).


3
Qualche motivo in particolare che consiglieresti questo approccio ES6 rispetto all'altro ( s = '#'.repeat(10)) dalla risposta di @ user4227915 sopra?
talemyn,

@talemyn Sintassi più semplice
Mendy

3

Versione che funziona in tutti i browser

Questa funzione fa quello che vuoi ed esegue molto più velocemente dell'opzione suggerita nella risposta accettata:

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

Lo usi in questo modo:

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

Per confrontare le prestazioni di questa funzione con quelle dell'opzione proposta nella risposta accettata, vedere questo Fiddle e questo Fiddle per i benchmark.

Versione solo per browser moderni

Nei browser moderni, ora puoi anche fare questo:

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

Questa opzione è ancora più veloce. Tuttavia, sfortunatamente non funziona in nessuna versione di Internet Explorer.

I numeri nella tabella specificano la prima versione del browser che supporta completamente il metodo:

inserisci qui la descrizione dell'immagine


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

Puoi anche aggiungere un polifill per Repeat per i browser più vecchi

    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

Basato sulle risposte di Hogan e Zero Trick Pony. Penso che questo dovrebbe essere sia veloce che flessibile per gestire bene la maggior parte dei casi d'uso:

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

Aggiungi qualche spiegazione in più alla tua risposta poiché uno snippet di codice stesso non fornisce una risposta.
Clijsters,

@Leandro Clever e minimizza l'elaborazione! +1
LMSingh,

Penso che volevi dire hash.length> = lunghezza
cipak

1

Puoi usare la prima riga della funzione come una riga se ti piace:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.