Створіть рядок змінної довжини, заповнену повторним символом


164

Отже, моє запитання задав хтось інший у його формі Java: Java - Створіть новий екземпляр String із заданою довжиною і заповнений конкретним символом. Найкраще рішення?

. . . але я шукаю його еквівалент JavaScript.

В основному, я хочу динамічно заповнювати текстові поля символами "#" на основі атрибута "maxlength" кожного поля. Отже, якщо вхід має maxlength="3", то поле буде заповнене "###".

В ідеалі було б щось на кшталт Java StringUtils.repeat("#", 10);, але, поки що, найкращий варіант, який я можу придумати, - це переглядати та додавати символи "#", по одному, до досягнення максимальної довжини. Я не можу похитнутись від відчуття, що існує більш ефективний спосіб зробити це.

Будь-які ідеї?

FYI - я не можу просто встановити значення вводу за замовчуванням у вході, оскільки символи "#" повинні очистити фокус, і, якщо користувач не ввів значення, його потрібно буде "поповнити" при розмитті. Це ступінь «поповнення», який я хвилюю


1
Ви робите це, щоб замаскувати текст поля введення?
Feisty Mango

@MatthewCox: Ні, це більше забезпечити візуальний показ максимальної довжини. У цьому випадку це набір полів телефонних номерів, розділених на 3 частини номера. Це показало б, що для перших 2 полів потрібно 3 цифри, а для останніх 4
tamyn

Відповіді:


303

Найкращий спосіб зробити це (що я бачив) - це

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

Це створює масив із заданою довжиною, а потім з'єднує його з заданою рядком для повторення. .join()Функція шанує довжину масиву , незалежно від того , чи мають елементи значення , присвоєне і невизначені значення відображаються як порожні рядки.

Вам потрібно додати 1 до потрібної довжини, оскільки розділовий рядок проходить між елементами масиву.


Прибив його. :) Мені просто потрібно було пам’ятати, щоб використовувати parseInt()на входах значення maxlength, перш ніж використовувати його для розміру масиву. Тільки те, що я шукав. . . Дякую!
Талемін

11
Зауважте, це рішення ДУЖЕ повільне. Це виглядає сексуально, але, мабуть, саме неправильний спосіб це зробити.
Хоган

23
нова repeatфункція, вбудована в String.prototype, зараз справляється з цим (ES6 +)
AlexMA

Хворий розчин. Дякую за це!
C4d

156

Спробуйте це: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Безумовно, найпростіша реалізація, але також найменш підтримувана, оскільки вона є частиною ECMAScript 6. Схоже, зараз вона підтримується лише у Firefox, Chrome та настільній версії Safari.
талемін

5
Якщо ви не заперечуєте проти використання лодашу , ви можете скористатися наступним: _.repeat('*',10);
Geraud Gratacap

4
Зараз 2018 рік, і ES6 налагоджений - це має бути прийнята відповідь. І якщо вам потрібно підтримати застарілі браузери для тих, хто не використовує Babel або щось подібне, ви можете використовувати lodash, як було сказано вище, або поліфайл для резервного копіювання.
seanTcoyote

@seanTcoyote Наскільки б я хотів, все ще є люди, яким доводиться боротися з IE 11 та веб-переглядами Adroid, жодна з яких не підтримує цей repeat()метод. З нетерпінням чекаю того дня, коли мені більше не доведеться їх дбати. . .
talemyn

На жаль, не сумісний з IE
Лоренцо Лерате

30

На жаль, хоча підхід Array.join, згаданий тут, короткий, він на 10 разів повільніше, ніж реалізація на основі рядка. Особливо погано виступає на великих струнах. Дивіться нижче, щоб отримати детальну інформацію про продуктивність.

На Firefox, Chrome, Node.js MacOS, Node.js Ubuntu та Safari, найшвидша реалізація, яку я протестував:

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

Це є багатослівним, тому, якщо ви хочете, щоб втручатися в реалізацію, ви можете піти з наївним підходом; він все ще виконує betweeb 2X до 10X краще, ніж підхід Array.join, а також швидше, ніж подвоєння впровадження для невеликих входів. Код:

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

Додаткова інформація:


1
Це ще набагато повільніше (на 2 - 3 порядки), ніж моє рішення.
Хоган

@Hogan Ваше рішення не створює заповнену рядок нізвідки. Ви створюєте його самостійно, а потім просто витягуєте підрядку.
СТАН

Цей підхід у 10 разів повільніше, ніж Array.join в Node.js для надзвичайно великих рядків.
Аншул Кока

21

Я б створив постійний рядок, а потім викликав би підрядку на ньому.

Щось на зразок

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

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

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

Трохи швидше теж.

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


1
Це дуже розумно! І це навіть працює з рядковими візерунками, що містять кілька символів.
Маркус

1
Просто перегляньте цю сторінку, тому що вона, як видається, отримує багато уваги і хотіла прокоментувати ваше рішення. Хоча мені, безумовно, подобається простота та швидкість вашого підходу, моя найбільша турбота про це була навколо технічного обслуговування / повторного використання. Хоча в моєму конкретному сценарії мені не потрібно було більше 4 символів, як загальна функція, використання рядка фіксованої довжини означає, що вам потрібно повернутися та оновити рядок, якщо у вашому випадку використання потрібно більше символів. Два інших рішення дозволяють досягти більшої гнучкості в цьому плані. Хоча +1 за швидкість.
Талемінь

1
О, і, на зворотній стороні (і я розумію, це справді більше стосується стилістичної проблеми, ніж програмної), підтримка рядка символів 30+, який коли-небудь використовуватиметься для 3-4 символів, не сиділа я також . . . знову ж таки, незначне питання щодо гнучкості рішення для різних випадків використання.
talemyn

@talemyn В ІТ - все - це компроміс. Майте рядок із 4 символами та зробіть його більшим або матимете рядок 30 символів, і не хвилюйтеся. Загалом, постійний рядок будь-якого розміру - навіть 1 к, - це невелике використання ресурсів на сучасних машинах.
Hogan

@Hogan - повністю згоден. . . і, це фактично частина причини, що я також не робив величезного акценту на швидкості. У моєму конкретному випадку я шукав три рядки довжиною 3, 3 та 4 символи. Хоча рішення Pointy було найповільнішим, оскільки струни були короткими, а їх було лише декілька, я пішов з ним, тому що мені сподобалося, що він був обтічним, легким для читання та легким у обслуговуванні. Зрештою, всі вони є хорошими рішеннями для різних варіацій питання. . . все залежить від пріоритетів для вашої конкретної ситуації.
талемінь


5

Відмінним варіантом ES6 буде padStartпуста рядок. Подобається це:

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

Примітка: це не буде працювати в IE (без полів).


3
Будь-яка причина, зокрема, що ви порекомендували б цей підхід ES6 порівняно з іншим ( s = '#'.repeat(10)) з відповіді @ user4227915 вище?
talemyn

@talemyn Простіший синтаксис
Менді

3

Версія, яка працює у всіх браузерах

Ця функція виконує те, що ви хочете, і виконує набагато швидше, ніж варіант, запропонований у прийнятій відповіді:

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

Ви використовуєте його так:

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

Щоб порівняти ефективність цієї функції з можливістю, запропонованою у прийнятій відповіді, див. Цей Fiddle та цей Fiddle для орієнтирів.

Версія лише для сучасних браузерів

У сучасних браузерах тепер ви також можете це зробити:

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

Цей варіант ще швидший. Однак, на жаль, він не працює в будь-якій версії Internet Explorer.

Цифри в таблиці вказують першу версію браузера, яка повністю підтримує метод:

введіть тут опис зображення


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

Ви також можете додати поліфункцію для повтору для старих браузерів

    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

Спираючись на відповіді Хогана та Нуля Тріка Поні. Я думаю, що це повинно бути досить швидким і гнучким, щоб добре обробляти випадки використання:

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

Будь ласка, додайте ще кілька пояснень до своєї відповіді, оскільки сам фрагмент коду не дає відповіді.
Clijsters

@Leandro Розумний та мінімізує обробку! +1
LMSingh

Я думаю, ви мали на увазі hash.length> = length
cipak

1

Ви можете використовувати перший рядок функції як однолінійний, якщо вам подобається:

function repeat(str, len) {
    while (str.length < len) str += str.substr(0, len-str.length);
    return str;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.