Utwórz ciąg o zmiennej długości, wypełniony powtarzającym się znakiem


164

Tak więc moje pytanie zostało zadane przez kogoś innego w jego formie Java : Java - Utwórz nową instancję String o określonej długości i wypełnioną określonym znakiem. Najlepsze rozwiązanie?

. . . ale szukam jego odpowiednika w JavaScript.

Zasadniczo chcę dynamicznie wypełniać pola tekstowe znakami „#” na podstawie atrybutu „maxlength” każdego pola. Tak więc, jeśli wejście ma maxlength="3", to pole zostanie wypełnione „###”.

Idealnie byłoby coś takiego jak Java StringUtils.repeat("#", 10);, ale jak dotąd najlepszą opcją, jaką przychodzi mi do głowy, jest zapętlanie i dodawanie znaków „#”, jeden po drugim, aż do osiągnięcia maksymalnej długości. Nie mogę pozbyć się wrażenia, że ​​jest na to skuteczniejszy sposób niż to.

Jakieś pomysły?

Do Twojej wiadomości - nie mogę po prostu ustawić wartości domyślnej w danych wejściowych, ponieważ znaki „#” muszą zostać wyczyszczone przy fokusie, a jeśli użytkownik nie wprowadził wartości, będą musiały zostać „uzupełnione” przy rozmyciu. Martwię się o krok „uzupełnienia”


1
Czy robisz to, aby zamaskować tekst pola wejściowego?
Feisty Mango

@MatthewCox: Nie, bardziej chodzi o wizualne przedstawienie maksymalnej długości. W tym przypadku jest to zestaw pól numeru telefonu, które są podzielone na 3 części numeru.
Pokazałoby

Odpowiedzi:


303

Najlepszym sposobem na to (jaki widziałem) jest

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

To tworzy tablicę o określonej długości, a następnie łączy ją z podanym ciągiem do powtórzenia. .join()Funkcja wyróżnieniem długości tablicy, niezależnie od tego, czy elementy mieć przypisane wartości, zaś wartości nieokreślone są prezentowane jako puste.

Musisz dodać 1 do żądanej długości, ponieważ ciąg separatora znajduje się między elementami tablicy.


Udało mi się to. :) Musiałem tylko pamiętać, aby użyć parseInt()wartości maxlength danych wejściowych przed użyciem jej do rozmiaru tablicy. Właśnie tego szukałem. . . dzięki!
talemyn

11
Uwaga, to rozwiązanie jest BARDZO powolne. Wygląda seksownie, ale prawdopodobnie jest to zły sposób na zrobienie tego.
Hogan

23
nowa repeatfunkcja wbudowana w String.prototype teraz to obsługuje (ES6 +)
AlexMA

Chore rozwiązanie. Dzięki za to!
C4d

156

Spróbuj: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Zdecydowanie najłatwiejsza implementacja, ale także najmniej obsługiwana, ponieważ jest częścią ECMAScript 6. Wygląda na to, że obecnie jest obsługiwana tylko w przeglądarkach Firefox, Chrome i Safari na komputer.
talemyn

5
Jeśli nie masz nic przeciwko używaniu lodash , możesz użyć następującego: _.repeat('*',10);
Geraud Gratacap,

4
Teraz mamy 2018 rok, a ES6 jest dobrze ugruntowana - to powinna być akceptowana odpowiedź. A jeśli potrzebujesz obsługi starszych przeglądarek dla tych, którzy nie używają Babel lub czegoś podobnego, możesz użyć lodash, jak wspomniano powyżej, lub polyfill do tworzenia kopii zapasowych.
seanTcoyote

@seanTcoyote Chociaż bardzo bym chciał, wciąż są ludzie, którzy muszą zmagać się z przeglądarkami IE 11 i Adroid's Webviews, z których żadna nie obsługuje tej repeat()metody. Z niecierpliwością czekam na dzień, w którym nie będę już musiał się nimi przejmować. . .
talemyn

Niestety nie jest kompatybilny z IE
Lorenzo Lerate

30

Niestety, chociaż wspomniane tutaj podejście Array.join jest zwięzłe, jest około 10 razy wolniejsze niż implementacja oparta na konkatenacji ciągów. Szczególnie słabo radzi sobie na dużych strunach. Zobacz poniżej pełne szczegóły dotyczące wydajności.

W przeglądarkach Firefox, Chrome, Node.js MacOS, Node.js Ubuntu i Safari najszybsza implementacja, którą przetestowałem, to:

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

To jest rozwlekłe, więc jeśli chcesz zwięzłej implementacji, możesz wybrać naiwne podejście; nadal działa od 2X do 10X lepiej niż podejście Array.join, a także jest szybszy niż implementacja podwajania dla małych danych wejściowych. 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;
}

Dalsza informacja:


1
Jest to wciąż DUŻO wolniejsze (o 2 do 3 rzędy wielkości) niż moje rozwiązanie.
Hogan

@Hogan Twoje rozwiązanie nie tworzy wypełnionego ciągu znikąd. Tworzysz go samodzielnie, a następnie po prostu wyodrębniasz podciąg.
StanE,

To podejście jest 10x wolniejsze niż Array.join w Node.js dla bardzo dużych łańcuchów.
Anshul Koka

21

Utworzyłbym ciąg stały, a następnie wywołałbym na nim podciąg.

Coś jak

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

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

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

Nieco szybciej też.

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


1
To bardzo sprytne! Działa nawet z wzorami ciągów zawierającymi wiele znaków.
Markus

1
Ponownie odwiedzam tę stronę, ponieważ wydaje się, że przyciąga ona dużo uwagi i chce skomentować Twoje rozwiązanie. Chociaż zdecydowanie podoba mi się prostota i szybkość twojego podejścia, moim największym zmartwieniem była konserwacja / ponowne użycie. Chociaż w moim konkretnym scenariuszu nie potrzebowałem więcej niż 4 znaków, jako funkcja ogólna, użycie łańcucha o stałej długości oznacza, że ​​musisz wrócić i zaktualizować ciąg, jeśli twój przypadek użycia kiedykolwiek potrzebuje więcej znaków. Pozostałe dwa rozwiązania pozwalają na większą elastyczność w tym zakresie. Jednak +1 za prędkość.
talemyn

1
Aha, i z drugiej strony (i zdaję sobie sprawę, że jest to bardziej kwestia stylistyczna niż programowa), utrzymywanie ponad 30-znakowego ciągu znaków, który będzie używany tylko przez 3-4 znaki, nie pasował do ja też. . . znowu drobny problem dotyczący elastyczności rozwiązania dla różnych przypadków użycia.
talemyn

@talemyn W IT wszystko jest kompromisem. Miej 4-znakowy ciąg i powiększ go lub miej 30-znakowy i nie martw się. Podsumowując, stały ciąg dowolnego rozmiaru - nawet 1k - to niewielkie zużycie zasobów na nowoczesnych maszynach.
Hogan

@Hogan - całkowicie się zgadzam. . . i to jest właściwie jeden z powodów, dla których nie położyłem dużego nacisku na prędkość. W moim konkretnym przypadku szukałem trzech ciągów o długości 3, 3 i 4 znaków. Chociaż rozwiązanie Pointy'ego było najwolniejsze, ponieważ struny były krótkie i było ich tylko kilka, zdecydowałem się na jego, ponieważ podobał mi się fakt, że jest usprawniony, łatwy do odczytania i łatwy w utrzymaniu. W końcu wszystkie są dobrymi rozwiązaniami dla różnych odmian pytania. . . wszystko będzie zależeć od priorytetów w twojej konkretnej sytuacji.
talemyn


5

Świetną opcją w ES6 byłby padStartpusty łańcuch. Lubię to:

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

Uwaga: to nie zadziała w IE (bez polyfill).


3
Czy jest jakiś konkretny powód, dla którego poleciłbyś to podejście ES6 s = '#'.repeat(10)zamiast drugiego ( ) z odpowiedzi @ user4227915 powyżej?
talemyn

@talemyn Prostsza składnia
Mendy

3

Wersja działająca we wszystkich przeglądarkach

Ta funkcja robi to, co chcesz i działa znacznie szybciej niż opcja sugerowana w zaakceptowanej odpowiedzi:

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

Używasz tego w ten sposób:

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

Aby porównać wydajność tej funkcji z opcją zaproponowaną w zaakceptowanej odpowiedzi, zobacz testy porównawcze tego Fiddle'a i tego Fiddle'a .

Wersja tylko dla nowoczesnych przeglądarek

W nowoczesnych przeglądarkach możesz teraz również to zrobić:

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

Ta opcja jest jeszcze szybsza. Jednak niestety nie działa w żadnej wersji przeglądarki Internet Explorer.

Liczby w tabeli określają pierwszą wersję przeglądarki, która w pełni obsługuje tę metodę:

wprowadź opis obrazu tutaj


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

W starszych przeglądarkach możesz także dodać wypełnienie tekstowe dla opcji Powtórz

    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

Na podstawie odpowiedzi Hogana i Zero Trick Pony. Myślę, że powinno to być zarówno szybkie, jak i wystarczająco elastyczne, aby dobrze obsłużyć większość przypadków użycia:

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

Dodaj więcej wyjaśnień do swojej odpowiedzi, ponieważ sam fragment kodu nie zawiera odpowiedzi.
Clijsters

@Leandro Clever i minimalizuje przetwarzanie! +1
LMSingh

Myślę, że miałeś na myśli hash.length> = length
cipak

1

Możesz użyć pierwszej linii funkcji jako linijki, jeśli chcesz:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.