Tekrarlanan bir karakterle dolu, değişken uzunlukta bir dize oluşturma


164

Yani, sorum burada Java formunda başka biri tarafından sorulmuştur: Java - Belirtilen uzunlukta ve belirli bir karakterle dolu yeni bir String örneği oluşturun. En iyi çözüm?

. . . ama JavaScript eşdeğerini arıyorum.

Temel olarak, her alanın "maxlength" özniteliğine dayalı olarak metin alanlarını dinamik olarak "#" karakterleriyle doldurmak istiyorum. Dolayısıyla, bir girdi varsa maxlength="3"alan "###" ile doldurulur.

İdeal olarak Java gibi bir şey olurdu StringUtils.repeat("#", 10);, ancak şimdiye kadar düşünebileceğim en iyi seçenek, maksimum uzunluğa ulaşılana kadar birer birer "#" karakterleri döngüye sokmak ve eklemektir. Bunu yapmanın daha etkili bir yolu olduğu hissini sallayamıyorum.

Herhangi bir fikir?

FYI - Girişte varsayılan bir değer ayarlayamıyorum çünkü "#" karakterlerinin odakta temizlenmesi gerekiyor ve kullanıcı bir değer girmediyse bulanıklıkta "yeniden doldurulması" gerekecek. Endişelendiğim "doldurma" adımı


1
Bunu bir giriş alanının metnini maskelemek için mi yapıyorsunuz?
Alıngan Mango

@MatthewCox: Hayır, maksimum uzunluğun görsel bir görüntüsünü sunmak daha fazlasıdır. Bu durumda, numaranın 3 kısmına bölünmüş bir dizi telefon numarası alanı içindir. İlk 2 alanın 3 basamağa ve son ihtiyaç 4'e ihtiyacı olduğunu gösterecektir.
talemyn

Yanıtlar:


303

Bunu yapmanın en iyi yolu (gördüğüm)

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

Bu, verilen uzunlukta bir dizi oluşturur ve daha sonra tekrarlamak için verilen dizeyle birleştirir. .join()Fonksiyon ne olursa olsun elemanları atanmış değerlere sahip olup olmadığı dizisi uzunluğunu onurlandırıyor ve tanımsız değerleri boş dizeleri olarak oluşturulur.

Ayırıcı dize dizi öğeleri arasında gittiğinden, istenen uzunluğa 1 eklemeniz gerekir .


Başarmak. :) Ben sadece parseInt()diziyi boyutlandırmak için kullanmadan önce girişler maxlength değeri kullanmayı hatırlamak gerekiyordu . Tam da aradığım şey . . . Teşekkürler!
talemyn

11
Bu çözüm ÇOK yavaştır. Seksi görünüyor ama muhtemelen bunu yapmanın yanlış yolu.
Hogan

23
repeatString.prototype'de yerleşik yeni işlev bunu şimdi ele alıyor (ES6 +)
AlexMA

Hasta çözüm. Bunun için teşekkürler!
C4d

156

Bunu deneyin: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Kesinlikle en kolay uygulama, aynı zamanda en az desteklenen, ECMAScript 6'nın bir parçası olduğu için. Şimdilik, şu anda yalnızca Safari'nin Firefox, Chrome ve masaüstü sürümünde destekleniyor.
talemyn

5
Lodash'ı kullanmanın bir sakıncası yoksa aşağıdakileri kullanabilirsiniz:_.repeat('*',10);
Geraud Gratacap

4
Şimdi 2018 ve ES6 iyi kurulmuş - bu kabul edilen cevap olmalı. Ve Babel veya benzeri bir şey kullanmayanlar için eski tarayıcıları desteklemeniz gerektiğinde, yukarıda belirtildiği gibi lodash veya yedekleme için bir çoklu dolgu kullanabilirsiniz.
seanTcoyote

@seanTcoyote İstediğim kadarıyla, IE 11 ve Adroid'in Webviews ile uğraşmak zorunda kalan insanlar var, ikisi de repeat()yöntemi desteklemiyor . Artık onları önemsememe gerek kalmayacağım günü dört gözle bekliyorum. . .
talemyn

Ne yazık ki, IE ile uyumlu değil
Lorenzo Lerate

30

Ne yazık ki, burada belirtilen Array.join yaklaşımı kısa olmasına rağmen, dize-birleştirme tabanlı bir uygulamadan yaklaşık 10 kat daha yavaştır. Özellikle büyük tellerde kötü performans gösterir. Tüm performans ayrıntıları için aşağıya bakın.

Firefox, Chrome, Node.js MacOS, Node.js Ubuntu ve Safari'de test ettiğim en hızlı uygulama:

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

Bu çok ayrıntılıdır, bu yüzden kısa bir uygulama istiyorsanız naif yaklaşımla gidebilirsiniz; Hala Array.join yaklaşımından 2X ila 10X arasında daha iyi performans gösterir ve ayrıca küçük girdiler için iki katına çıkma uygulamasından daha hızlıdır. Kod:

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

Daha fazla bilgi:


1
Bu hala benim çözümümden ÇOK daha yavaş (2 ila 3 büyüklükte).
Hogan

@Hogan Çözümünüz hiçbir yerden doldurulmuş bir dize oluşturmuyor. Kendiniz oluşturun ve sonra bir alt dize ayıklayın.
StanE

Bu yaklaşım, çok büyük dizeler için Node.js'de Array.join'e göre 10 kat daha yavaştır.
Anshul Koka

21

Sabit bir dize oluşturmak ve sonra alt dize çağırır.

Gibi bir şey

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

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

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

Biraz daha hızlı.

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


1
Bu çok akıllı! Ve hatta birden fazla karakter içeren dize desenleriyle bile çalışır.
Markus

1
Sadece bu sayfayı tekrar ziyaret ediyor çünkü çok fazla ilgi görmeye devam ediyor ve çözümünüz hakkında yorum yapmak istiyor. Yaklaşımınızın basitliğini ve hızını kesinlikle sevmeme rağmen, en büyük endişem bakım / yeniden kullanımdı. Özel senaryomda, genel bir işlev olarak 4'ten fazla karaktere ihtiyacım yoktu, sabit uzunluklu bir dize kullanmak, kullanım durumunuz daha fazla karaktere ihtiyaç duyuyorsa, geri dönüp dizeyi güncellemeniz gerektiği anlamına gelir. Diğer iki çözüm bu konuda daha fazla esneklik sağlar. Hız için +1 olsa da.
talemyn

1
Oh, ve kapak tarafında (ve bunun programlı olandan çok daha stilistik bir endişe olduğunu anlıyorum), sadece 3-4 karakter için kullanılacak 30'dan fazla karakter dizisini korumak, ben de değil . . . yine, çeşitli kullanım durumları için çözümün esnekliği ile ilgili küçük bir sorun.
talemyn

@talemyn BT'de her şey bir değiş tokuş. 4 karakterli bir dizeye sahip olun ve daha büyük yapın veya 30 karakterli bir dizeye sahip olun ve endişelenmeyin. Sonuçta, herhangi bir boyutta sabit bir dizi - 1k bile, modern makinelerde küçük kaynak kullanımıdır.
Hogan

@Hogan - tamamen katılıyorum. . . ve bu aslında hıza da büyük önem vermeme nedenimin bir parçası. Özel kullanım durumumda, 3, 3 ve 4 karakter uzunluğunda üç dize arıyordum. Pointy'nin çözümü en yavaş olsa da, dizeler kısa olduğu ve sadece birkaç tanesi olduğu için onunla gittim çünkü aerodinamik, okunması kolay ve bakımı kolay olması hoşuma gitti. Sonuçta, hepsi sorunun farklı varyasyonları için iyi çözümlerdir. . . her şey sizin özel durumunuz için önceliklerin ne olduğuna bağlı olacaktır.
talemyn


5

padStartBoş bir dize için harika bir ES6 seçeneği olabilir . Bunun gibi:

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

Not: Bu IE'de çalışmaz (çoklu dolgu olmadan).


3
Bu ES6 yaklaşımını s = '#'.repeat(10)yukarıdaki @ user4227915'in cevabından diğerine ( ) tavsiye etmenizin herhangi bir nedeni var mı?
talemyn

@talemyn Simpler sözdizimi
Mendy

3

Tüm tarayıcılarda çalışan sürüm

Bu işlev istediğinizi yapar ve kabul edilen cevapta önerilen seçenekten çok daha hızlı performans gösterir:

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

Bu şekilde kullanırsınız:

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

Bu işlevin performansını, kabul edilen yanıtta önerilen seçenekle karşılaştırmak için, karşılaştırmalar için bu Fiddle'a ve bu Fiddle'a bakın.

Yalnızca modern tarayıcılar için sürüm

Modern tarayıcılarda artık şunları da yapabilirsiniz:

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

Bu seçenek daha da hızlı. Ancak, ne yazık ki herhangi bir Internet explorer sürümünde çalışmıyor.

Tablodaki sayılar, yöntemi tam olarak destekleyen ilk tarayıcı sürümünü belirtir:

resim açıklamasını buraya girin


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

Eski tarayıcılar için Tekrarlama için bir çoklu dolgu da ekleyebilirsiniz

    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

Hogan ve Zero Trick Pony'nin cevaplarına dayanarak. Bence bu, çoğu kullanım durumunu iyi işleyebilecek kadar hızlı ve esnek olmalıdır:

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

Lütfen kod pasajının kendisi bir yanıt sağlamadığından cevabınıza biraz daha açıklama ekleyin.
Clijsters

@Leandro Zeki ve işlemeyi en aza indirir! +1
LMSingh

Sanırım demek hash.length> = uzunluk
cipak

1

İsterseniz işlevin ilk satırını tek astar olarak kullanabilirsiniz:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.