Créer une chaîne de longueur variable, remplie d'un caractère répété

164

Donc, ma question a été posée par quelqu'un d'autre sous sa forme Java ici: Java - Créer une nouvelle instance String avec une longueur spécifiée et remplie d'un caractère spécifique. Meilleure solution?

. . . mais je cherche son équivalent JavaScript.

Fondamentalement, je souhaite remplir dynamiquement les champs de texte avec des caractères "#", en fonction de l'attribut "maxlength" de chaque champ. Donc, si une entrée a maxlength="3", alors le champ sera rempli avec "###".

Idéalement, il y aurait quelque chose comme Java StringUtils.repeat("#", 10);, mais, jusqu'à présent, la meilleure option à laquelle je puisse penser est de boucler et d'ajouter les caractères "#", un à la fois, jusqu'à ce que la longueur maximale soit atteinte. Je ne peux pas me débarrasser du sentiment qu'il existe un moyen plus efficace de le faire que cela.

Des idées?

FYI - Je ne peux pas simplement définir une valeur par défaut dans l'entrée, car les caractères "#" doivent être effacés lors de la mise au point et, si l'utilisateur n'a pas entré de valeur, ils devront être "remplis" sur le flou. C'est l'étape de "recharge" qui me préoccupe

talemyn
la source
1
Faites-vous cela pour masquer le texte d'un champ de saisie?
Feisty Mango
@MatthewCox: Non, il s'agit plus de fournir un affichage visuel de maxlength. Dans ce cas, il s'agit d'un ensemble de champs de numéro de téléphone qui sont divisés en 3 parties du numéro. Cela montrerait que les 2 premiers champs ont besoin de 3 chiffres et les derniers de 4.
talemyn
doublon possible de Repeat String - Javascript
Felix Kling

Réponses:

303

La meilleure façon de faire cela (que j'ai vue) est

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

Cela crée un tableau avec la longueur donnée, puis le joint à la chaîne donnée à répéter. La .join()fonction honore la longueur du tableau indépendamment du fait que les éléments aient ou non des valeurs assignées, et les valeurs non définies sont rendues sous forme de chaînes vides.

Vous devez ajouter 1 à la longueur souhaitée car la chaîne de séparation passe entre les éléments du tableau.

Pointu
la source
J'y suis arrivé. :) J'avais juste besoin de me rappeler d'utiliser parseInt()la valeur maxlength des entrées avant de l'utiliser pour dimensionner le tableau. Exactement ce que je cherchais . . . Merci!
talemyn
11
Notez que cette solution est TRÈS lente. Cela a l'air sexy, mais ce n'est probablement pas la bonne façon de le faire.
Hogan
23
la nouvelle repeatfonction intégrée à String.prototype gère cela maintenant (ES6 +)
AlexMA
Solution malade. Merci pour cela!
C4d
156

Essayez ceci: P

s = '#'.repeat(10)

document.body.innerHTML = s


la source
4
Certainement la mise en œuvre la plus simple, mais aussi la moins prise en charge, car elle fait partie d'ECMAScript 6. On dirait que, pour le moment, elle n'est prise en charge que dans Firefox, Chrome et la version de bureau de Safari.
talemyn
5
Si cela ne vous dérange pas d'utiliser lodash , vous pouvez utiliser ce qui suit: _.repeat('*',10);
Geraud Gratacap
4
Nous sommes en 2018 maintenant et ES6 est bien établi - cela devrait être la réponse acceptée. Et en cas de besoin de prendre en charge les navigateurs hérités pour ceux qui n'utilisent pas Babel ou quelque chose de similaire, vous pouvez utiliser lodash comme mentionné ci-dessus, ou un polyfill pour la sauvegarde.
seanTcoyote
@seanTcoyote Autant que j'aimerais, il y a encore des gens qui doivent faire face à IE 11 et Webviews d'Adroid, qui ne supportent pas la repeat()méthode. Dans l'attente du jour où je n'aurai plus à me soucier d'eux, moi-même. . .
talemyn
Malheureusement, non compatible avec IE
Lorenzo Lerate
30

Malheureusement, bien que l'approche Array.join mentionnée ici soit laconique, elle est environ 10 fois plus lente qu'une implémentation basée sur la concaténation de chaînes. Il fonctionne particulièrement mal sur les grosses cordes. Voir ci-dessous pour plus de détails sur les performances.

Sur Firefox, Chrome, Node.js MacOS, Node.js Ubuntu et Safari, l'implémentation la plus rapide que j'ai testée était:

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

C'est verbeux, donc si vous voulez une implémentation laconique, vous pouvez opter pour l'approche naïve; il fonctionne toujours entre 2X et 10X mieux que l'approche Array.join, et est également plus rapide que l'implémentation du doublement pour les petites entrées. Code:

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

Informations complémentaires:

Poney Zero Trick
la source
1
C'est encore BEAUCOUP plus lent (de 2 à 3 ordres de grandeur) que ma solution.
Hogan
@Hogan Votre solution ne crée pas de chaîne remplie de nulle part. Vous le créez vous-même puis extrayez simplement une sous-chaîne.
StanE
Cette approche est 10 fois plus lente que Array.join dans Node.js pour les chaînes extrêmement volumineuses.
Anshul Koka
21

Je créerais une chaîne constante, puis j'appellerais une sous-chaîne dessus.

Quelque chose comme

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

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

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

Un peu plus vite aussi.

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

Hogan
la source
1
C'est très intelligent! Et cela fonctionne même avec des modèles de chaîne contenant plusieurs caractères.
Markus
1
Je revisite simplement cette page car elle semble continuer à attirer beaucoup d'attention et je voulais commenter votre solution. Bien que j'apprécie vraiment la simplicité et la rapidité de votre approche, ma plus grande préoccupation concernait la maintenance / réutilisation. Alors que dans mon scénario spécifique, je n'avais pas besoin de plus de 4 caractères, en tant que fonction générique, l'utilisation d'une chaîne de longueur fixe signifie que vous devez revenir et mettre à jour la chaîne, si votre cas d'utilisation a besoin de plus de caractères. Les deux autres solutions permettent une plus grande flexibilité à cet égard. +1 pour la vitesse, cependant.
talemyn
1
Oh, et, d'un autre côté (et je me rends compte que c'est vraiment plus une préoccupation stylistique, qu'une question programmatique), le maintien d'une chaîne de plus de 30 caractères qui ne sera jamais utilisée que pour 3-4 caractères ne convenait pas. moi non plus . . . encore une fois, un problème mineur concernant la flexibilité de la solution pour divers cas d'utilisation.
talemyn
@talemyn En informatique, tout est un compromis. Avoir une chaîne de 4 caractères et l'agrandir ou avoir une chaîne de 30 caractères et ne vous inquiétez pas. Dans l'ensemble, une chaîne constante de toute taille - même 1k, est une utilisation minime des ressources sur les machines modernes.
Hogan
@Hogan - tout à fait d'accord. . . Et c'est en partie la raison pour laquelle je n'ai pas non plus mis l'accent sur la vitesse. Dans mon cas d'utilisation spécifique, je recherchais trois chaînes de 3, 3 et 4 caractères. Alors que la solution de Pointy était la plus lente, puisque les cordes étaient courtes et qu'il n'y en avait que quelques-unes, j'ai choisi la sienne parce que j'aimais le fait qu'elle soit rationalisée, facile à lire et à entretenir. En fin de compte, ce sont toutes de bonnes solutions pour différentes variantes de la question. . . tout dépendra des priorités pour votre situation spécifique.
talemyn
5

Une excellente option ES6 serait d'utiliser padStartune chaîne vide. Comme ça:

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

Remarque: cela ne fonctionnera pas dans IE (sans polyfill).

Mendy
la source
3
Une raison en particulier pour laquelle vous recommanderiez cette approche ES6 par rapport à l 'autre ( s = '#'.repeat(10)) de la réponse de @ user4227915 ci - dessus?
talemyn
@talemyn Simpler syntax
Mendy
3

Version qui fonctionne dans tous les navigateurs

Cette fonction fait ce que vous voulez et fonctionne beaucoup plus rapidement que l'option suggérée dans la réponse acceptée:

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

Vous l'utilisez comme ceci:

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

Pour comparer les performances de cette fonction avec celles de l'option proposée dans la réponse acceptée, voir ce Fiddle et ce Fiddle pour les repères.

Version pour les navigateurs modernes uniquement

Dans les navigateurs modernes, vous pouvez désormais également faire ceci:

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

Cette option est encore plus rapide. Cependant, malheureusement, cela ne fonctionne dans aucune version d'Internet Explorer.

Les chiffres du tableau indiquent la première version du navigateur qui prend entièrement en charge la méthode:

entrez la description de l'image ici

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

Vous pouvez également ajouter un polyfill pour Repeat pour les anciens navigateurs

    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
la source
2

Basé sur les réponses de Hogan et Zero Trick Pony. Je pense que cela devrait être à la fois suffisamment rapide et flexible pour bien gérer la plupart des cas d'utilisation:

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
la source
Veuillez ajouter quelques explications supplémentaires à votre réponse car un extrait de code lui-même ne fournit pas de réponse.
Clijsters
@Leandro Clever et minimise le traitement! +1
LMSingh
Je pense que vous vouliez dire hash.length> = length
cipak
1

Vous pouvez utiliser la première ligne de la fonction comme une seule ligne si vous le souhaitez:

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