Создайте строку переменной длины, заполненную повторяющимся символом


164

Итак, мой вопрос был задан кем-то еще в его форме Java здесь: Java - создайте новый экземпляр String с заданной длиной и заполненный определенным символом. Лучшее решение?

, , , но я ищу его эквивалент JavaScript.

По сути, я хочу динамически заполнять текстовые поля символами «#», основываясь на атрибуте «maxlength» каждого поля. Таким образом, если вход имеет maxlength="3", то поле будет заполнено "###".

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

Любые идеи?

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


1
Вы делаете это, чтобы замаскировать текст поля ввода?
Feisty Mango

@ MatthewCox: Нет, это больше, чтобы обеспечить визуальное отображение максимальной длины. В этом случае это для набора полей телефонных номеров, которые разделены на 3 части номера. Это показало бы, что первые 2 поля должны
иметь

возможный дубликат повторяющейся строки - Javascript
Феликс Клинг

Ответы:


303

Лучший способ сделать это (что я видел) это

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

Это создает массив с заданной длиной, а затем соединяет его с заданной строкой для повторения. .join()Функция чтит длину массива , независимо от того , имеют ли элементы значения , присвоенное и неопределенные значения отображаются как пустые строки.

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


Успешно справился. :) Мне просто нужно помнить, чтобы использовать parseInt()на входе значение максимальной длины, прежде чем использовать его для размера массива. Как раз то, что я искал. , , Спасибо!
Талемын

11
Обратите внимание, это решение очень медленное. Это выглядит сексуально, но, вероятно, это совершенно неправильный способ сделать это.
Хоган

23
новая repeatфункция, встроенная в String.prototype, обрабатывает это сейчас (ES6 +)
AlexMA

Больное решение. Спасибо за это!
C4d

156

Попробуйте это: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
Определенно самая простая реализация, но также и наименее поддерживаемая, поскольку она является частью ECMAScript 6. Похоже, что в настоящее время она поддерживается только в Firefox, Chrome и настольной версии Safari.
Талемын

5
Если вы не возражаете против использования lodash , вы можете использовать следующее: _.repeat('*',10);
Geraud Gratacap

4
Сейчас 2018 год, и ES6 хорошо зарекомендовал себя - это должен быть принятый ответ. А в случае необходимости поддержки устаревших браузеров для тех, кто не использует Babel или что-то подобное, вы можете использовать lodash, как упомянуто выше, или polyfill для резервного копирования.
seanTcoyote

@seanTcoyote Как бы мне ни хотелось, все еще есть люди, которым приходится бороться с IE 11 и веб-представлениями Adroid, но ни один из них не поддерживает этот repeat()метод. С нетерпением жду того дня, когда я больше не буду заботиться о них. , ,
Талемын,

К сожалению, не совместим с 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);
};

Это многословно, поэтому, если вам нужна краткая реализация, вы можете пойти наивным подходом; он по-прежнему работает лучше от 2 до 10 раз, чем подход 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 В ИТ все является компромиссом. Иметь 4-символьную строку и сделать ее больше или иметь 30-символьную строку и не беспокоиться. В целом, постоянная строка любого размера - даже 1 КБ - это незначительное использование ресурсов на современных машинах.
Хоган

@ Хоган - полностью согласен. , , и это на самом деле одна из причин того, что я не уделял большого внимания скорости тоже. В моем конкретном случае использования я искал три строки длиной 3, 3 и 4 символа. Хотя решение Pointy было самым медленным, поскольку строки были короткими, а их было всего несколько, я выбрал его, потому что мне нравился тот факт, что он был оптимизирован, легок для чтения и удобен в обслуживании. В конце концов, все они являются хорошими решениями для разных вариантов вопроса. , , все будет зависеть от приоритетов вашей конкретной ситуации.
Талемын


5

Отличным вариантом ES6 будет padStartпустая строка. Как это:

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

Примечание: это не будет работать в IE (без полифилла).


3
В частности, есть ли причина, по которой вы бы рекомендовали этот подход ES6 вместо другого ( s = '#'.repeat(10)) из ответа @ user4227915 выше?
Талемын

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

Чтобы сравнить производительность этой функции с опцией, предложенной в принятом ответе, см. Эту скрипку и эту скрипку для эталонных тестов.

Версия только для современных браузеров

В современных браузерах вы также можете сделать это:

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

Основано на ответах от Hogan и Zero Trick Pony. Я думаю, что это должно быть достаточно быстрым и гибким, чтобы хорошо обрабатывать большинство случаев использования

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 Умный и сводит к минимуму обработку! +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.