创建一个长度可变的字符串,其中填充有重复字符。

226

因此,我的问题已经在这里以Java形式被其他人提出:Java - Create a new String instance with specified length and filled with specific character. Best solution?

但我正在寻找它的JavaScript等效物。

基本上,我想根据每个字段的“maxlength”属性动态填充文本字段,使其填充为“#”字符。因此,如果输入框有maxlength="3",则该字段将填充为“###”。

理想情况下,应该有类似于Java中的StringUtils.repeat("#", 10);的东西,但是到目前为止,我能想到的最好的选择是循环遍历并逐个添加“#”字符,直到达到最大长度。我无法摆脱比这更有效的方法的感觉。

有什么建议吗?

FYI-我不能简单地设置输入框中的默认值,因为“#”字符需要在焦点清除,并且如果用户没有输入值,则需要在模糊时进行“重新填充”。 我关心"refill"这一步。


1
你这样做是为了掩盖输入字段的文本吗? - Matthew Cox
@MatthewCox:不,这更多是为了提供maxlength的可视化显示。在这种情况下,它是用于一组电话号码字段,这些字段分为号码的3个部分。它将显示前两个字段需要3位数字,最后一个字段需要4位数字。 - talemyn
可能是 Repeat String - Javascript 的重复问题。 - Felix Kling
今天,placeholder 可能是推荐的。将其应用于所有具有 maxlength<input> 看起来像是 document.querySelectorAll("[maxlength]").forEach((element) => element.placeholder = "#".repeat(element.maxLength)); - Sebastian Simon
12个回答

379

我见过的最好方法是这样做

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

这将创建一个给定长度的数组,然后使用给定字符串连接它以重复。无论元素是否被赋值,.join()函数都会尊重数组长度,并且未定义的值将呈现为空字符串。

由于分隔符字符串位于数组元素之间,因此您必须将期望长度加1。


做得好。我只需要记得在使用输入的maxlength值来调整数组大小之前,对其使用parseInt()。正是我正在寻找的……谢谢! - talemyn
13
请注意,这个解决方案非常慢。它看起来很酷,但很可能完全不是做这件事的正确方式。 - Hogan
44
现在(ES6+),String.prototype中新增了一个名为repeat的函数,用来处理这个问题。 - AlexMA
病态的解决方案。感谢它! - C4d
仅供参考。repeat() 的速度快了90%。padEnd() 也快了90%(使用 repeat 是最快的)。 - Patrice Thimothee

300

试着尝试一下 :P

s = '#'.repeat(10)

document.body.innerHTML = s


6
这是最简单的实现方式,但也得到了最少的支持,因为它是 ECMAScript 6 的一部分。目前看来,只有 Firefox、Chrome 和桌面版 Safari 支持它。 - talemyn
6
如果您不介意使用lodash,您可以使用以下代码:_.repeat('*',10); 它将重复输出10个星号(*)字符。 - Geraud Gratacap
9
现在是2018年,ES6已经很成熟了 - 这应该是被接受的答案。如果需要支持那些不使用Babel或类似工具的用户使用旧版浏览器,可以像上面提到的那样使用lodash,或者备用方案使用polyfill。 - seanTcoyote
@seanTcoyote 尽管我很想这样做,但仍有人必须应对IE 11和Adroid的Webviews,它们都不支持repeat()方法。期待有一天我自己也不必再关心它们了... - talemyn
很遗憾,不兼容IE。 - Lorenzo Lerate
1
现在肯定是正确的答案。 - stackers

56

今天阅读此内容的任何人都可以得到最佳答案。 - Joshua

31

很遗憾,虽然在这里提到的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);
};

如果你想要一个简短的实现,可以选择朴素的方法;它仍然比Array.join方法快2倍到10倍,并且对于小数据输入,也比加倍法更快。 代码:

// 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
1
@Hogan,你的解决方案并不是从无处创建一个填充字符串。你需要自己创建它,然后提取一个子字符串。 - StanE
这种方法在处理极大字符串时比Node.js中的Array.join慢10倍。 - Anshuul Kai

24
我会创建一个常量字符串,然后在它上面调用子字符串(substring)方法。
类似这样:
var hashStore = '########################################';

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

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

速度稍微更快一些。

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


1
这非常聪明!它甚至可以处理包含多个字符的字符串模式。 - Markus
1
只是回顾这个页面,因为它似乎一直受到很多关注,并想评论您的解决方案。虽然我绝对喜欢您的方法的简单性和速度,但我最担心的是维护/重用问题。虽然在我的具体情况下,我不需要超过4个字符,但作为通用函数,使用固定长度字符串意味着如果您的用例需要更多字符,您必须返回并更新该字符串。另外两个解决方案在这方面提供了更多的灵活性。不过速度加1。 - talemyn
1
哦,另一方面(我意识到这更多是风格上的问题,而不是编程上的问题),维护一个只会用于3-4个字符的30+字符字符串也让我感到不舒服...再次强调,这只是关于解决方案在各种用例中灵活性的一个小问题。 - talemyn
在IT领域,一切都是权衡取舍。将一个由4个字符组成的字符串变大还是使用一个由30个字符组成的字符串而不必担心呢?总的来说,即使是1k大小的常量字符串,在现代计算机上也只占用微小的资源。 - Hogan
@Hogan - 完全同意...这也是我没有过多强调速度的原因之一。在我的具体用例中,我正在寻找长度为3、3和4个字符的三个字符串。虽然Pointy的解决方案最慢,但由于字符串很短且只有几个,我选择了他的方案,因为我喜欢它的简洁、易读和易于维护。最终,它们都是针对不同问题变体的好解决方案...这将完全取决于您特定情况下的优先事项。 - talemyn
显示剩余4条评论

15

一个很好的ES6选项是使用padStart函数来填充一个空字符串。像这样:

一个很好的ES6选项是使用padStart函数来填充一个空字符串。像这样:

var str = ''.padStart(10, "#");
注意:这在IE中不起作用(需要一个polyfill)。

6
相比于 @user4227915 上面的那种方法(s = '#'.repeat(10)),你会有什么特别的原因推荐这个 ES6 的方法呢? - talemyn
FYI,padStart和repeat函数会得到不同的结果。 - Michael Harley
太棒了,我不知道我们有这个作为本地方法! - Technotronic
@MichaelHarley 怎么做? '#'.repeat(10) === ''.padStart(10, "#"); - EricLaw
@EricLaw repeatpadStart有不同的用例。对于空字符串?它们'有点儿'相同。对于需要确切长度的动态字符串?你绝对需要使用padStartpadEnd而不是repeat,尽管你可以通过额外的逻辑来复制相同的结果。 - Michael Harley

4

适用于所有浏览器的版本

这个函数可以实现您想要的功能,并且比接受答案中建议的选项执行速度更快:

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中都无法使用。

表格中的数字指定了完全支持该方法的第一个浏览器版本:

enter image description here


在我的浏览器(Vivaldi 2.6.1566.49(稳定通道)(64位))中,您的解决方案所需的时间大约是被接受答案的两倍。 - markus s
@markuss:今天我在最新版本的Chrome中运行基准测试时,结果大致相同。请注意,我的回答已经超过4年了,因此性能差异可能是在这4年期间发生的更新的结果... - John Slegers

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

您还可以为旧浏览器添加 Repeat 的 polyfill


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

3

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

请在您的答案中添加更多的解释,因为代码片段本身并不能提供答案。 - Clijsters
@Leandro 聪明而且最小化处理!+1 - LMSingh
我认为你的意思是 hash.length >= length。 - cipak

1

我会做

Buffer.alloc(length, character).toString()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接