สร้างสตริงที่มีความยาวผันแปรได้เต็มไปด้วยอักขระซ้ำ


164

ดังนั้นคำถามของฉันถูกถามโดยคนอื่นในรูปแบบ Java ที่นี่: Java - สร้างอินสแตนซ์สตริงใหม่ที่มีความยาวที่ระบุและเต็มไปด้วยอักขระที่เฉพาะเจาะจง ทางออกที่ดีที่สุด?

. . . แต่ฉันกำลังมองหาจาวาสคริปต์ที่เทียบเท่า

โดยทั่วไปฉันต้องการเติมฟิลด์ข้อความด้วยอักขระ "#" แบบไดนามิกโดยยึดตามแอตทริบิวต์ "maxlength" ของแต่ละฟิลด์ ดังนั้นหากมีการป้อนข้อมูลmaxlength="3"แล้วฟิลด์จะถูกเติมด้วย "###"

จะเป็นการดีที่จะมีบางสิ่งบางอย่างเช่น Java StringUtils.repeat("#", 10);แต่จนถึงตอนนี้ตัวเลือกที่ดีที่สุดที่ฉันนึกได้คือการวนซ้ำและผนวกอักขระ "#" ครั้งละหนึ่งตัวจนกว่าจะถึงความยาวสูงสุด ฉันไม่สามารถสั่นคลอนความรู้สึกว่ามีวิธีที่มีประสิทธิภาพมากกว่าที่จะทำ

ความคิดใด ๆ

FYI - ฉันไม่สามารถกำหนดค่าเริ่มต้นในอินพุตได้เพียงเพราะอักขระ "#" จำเป็นต้องล้างโฟกัสและหากผู้ใช้ไม่ได้ป้อนค่าจะต้อง "เติม" เบลอ เป็นขั้นตอน "เติมเงิน" ที่ฉันกังวล


1
คุณกำลังทำสิ่งนี้เพื่อปกปิดข้อความของฟิลด์อินพุตหรือไม่?
Feisty Mango

@MatthewCox: ไม่มันเป็นมากกว่าการแสดงภาพความยาวสูงสุด ในกรณีนี้มีไว้สำหรับเขตข้อมูลหมายเลขโทรศัพท์ที่แบ่งออกเป็น 3 ส่วนของหมายเลข มันจะแสดงให้เห็นว่า 2 ฟิลด์แรกต้องการ 3 หลักและความต้องการสุดท้าย 4
talemyn

สำเนาซ้ำของสตริงซ้ำ - Javascript
Felix Kling

คำตอบ:


303

วิธีที่ดีที่สุดในการทำเช่นนี้ (ที่ฉันเคยเห็น) คือ

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

ที่สร้างอาร์เรย์ที่มีความยาวที่กำหนดแล้วรวมกับสตริงที่กำหนดเพื่อทำซ้ำ .join()ฟังก์ชั่นได้รับเกียรตินิยมยาวอาร์เรย์โดยไม่คำนึงว่าองค์ประกอบที่มีค่าที่ได้รับมอบหมายและค่านิยมที่ไม่ได้กำหนดจะกลายเป็นสตริงที่ว่างเปล่า

คุณต้องเพิ่ม 1 ลงในความยาวที่ต้องการเนื่องจากสตริงตัวคั่นจะอยู่ระหว่างองค์ประกอบอาร์เรย์


ถูกจับมัน :) ฉันแค่ต้องจำไว้ว่าให้ใช้parseInt()กับค่า maxlength อินพุตก่อนที่จะใช้มันเพื่อปรับขนาดอาร์เรย์ สิ่งที่ฉันกำลังมองหา . . ขอบคุณ!
talemyn

11
หมายเหตุวิธีนี้ช้ามาก มันดูเซ็กซี่ แต่อาจเป็นวิธีที่ผิดในการทำเช่นนี้
โฮแกน

23
repeatฟังก์ชั่นใหม่ที่สร้างขึ้นใน String.prototype จัดการตอนนี้ (ES6 +)
AlexMA

วิธีการแก้ปัญหาป่วย ขอบคุณสำหรับมัน!
C4d

156

ลองดูสิ: P

s = '#'.repeat(10)

document.body.innerHTML = s


4
การใช้งานที่ง่ายที่สุดอย่างแน่นอน แต่ก็ยังได้รับการสนับสนุนน้อยที่สุดเนื่องจากเป็นส่วนหนึ่งของ ECMAScript 6 ดูเหมือนตอนนี้จะรองรับเฉพาะใน Firefox, Chrome และเดสก์ท็อปรุ่น Safari
talemyn

5
หากคุณไม่รังเกียจการใช้lodashคุณสามารถใช้สิ่งต่อไปนี้: _.repeat('*',10);
Geraud Gratacap

4
มันคือปี 2018 และ ES6 ได้รับการยอมรับเป็นอย่างดี - นี่ควรเป็นคำตอบที่ยอมรับได้ และในกรณีที่ต้องการสนับสนุนเบราว์เซอร์รุ่นเก่าสำหรับผู้ที่ไม่ได้ใช้ Babel หรือสิ่งที่คล้ายกันคุณสามารถใช้ lodash ตามที่กล่าวไว้ข้างต้นหรือ polyfill สำหรับการสำรองข้อมูล
seanTcoyote

@ seanTcoyote มากเท่าที่ฉันต้องการยังมีคนที่ต้องต่อสู้กับ IE 11 และ Webviews ของ Adroid ซึ่งไม่สนับสนุนrepeat()วิธีการนี้ รอวันที่ฉันไม่ต้องสนใจพวกเขาอีกต่อไปฉันเอง . .
talemyn

น่าเสียดายที่ไม่สามารถใช้งานร่วมกับ IE
Lorenzo Lerate

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

นี่คือ verbose ดังนั้นหากคุณต้องการใช้งานสั้น ๆ คุณสามารถไปด้วยวิธีไร้เดียงสา; มันยังคงทำงานได้ดีกว่า 2X ถึง 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 โซลูชันของคุณไม่ได้สร้างสตริงที่เติมจากที่ไหนเลย คุณสร้างด้วยตัวคุณเองและจากนั้นก็แยกสตริงย่อย
StanE

วิธีนี้ช้ากว่า Array.join 10 เท่าใน Node.js สำหรับสตริงที่มีขนาดใหญ่มาก
Anshul Koka

21

ฉันจะสร้างสตริงคงที่แล้วเรียกสตริงย่อยที่มัน

สิ่งที่ต้องการ

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
โอ้และในอีกด้านหนึ่ง (และฉันรู้ว่านี่เป็นเรื่องเกี่ยวกับโวหารมากกว่าการเขียนโปรแกรม) รักษาสตริงตัวละคร 30+ ตัวที่จะใช้กับตัวละคร 3-4 ตัวได้ไม่ดีนัก ฉันทั้ง . . อีกครั้งเป็นปัญหาเล็กน้อยเกี่ยวกับความยืดหยุ่นของการแก้ปัญหาสำหรับกรณีการใช้งานที่หลากหลาย
talemyn

@talemyn ในไอทีทุกอย่างเป็นการแลกเปลี่ยน มีสตริงอักขระ 4 ตัวและทำให้ใหญ่ขึ้นหรือมีสตริงอักขระ 30 ตัวและไม่ต้องกังวล สรุปแล้วคือขนาดคงที่ทุกขนาด - แม้แต่ 1k คือการใช้ทรัพยากรเพียงเล็กน้อยบนเครื่องจักรที่ทันสมัย
โฮแกน

@Hogan - เห็นด้วยทั้งหมด . . และนั่นเป็นส่วนหนึ่งของเหตุผลที่ฉันไม่ได้ให้ความสำคัญกับความเร็วมากนัก ในกรณีการใช้งานเฉพาะของฉันฉันกำลังมองหาสามสายอักขระที่มีความยาว 3, 3 และ 4 ตัว ในขณะที่วิธีแก้ปัญหาของ Pointy นั้นช้าที่สุดเนื่องจากสายสั้นและมีเพียงไม่กี่ตัวเท่านั้นฉันไปกับเขาเพราะฉันชอบความจริงที่ว่ามันเพรียวลมง่ายต่อการอ่านและง่ายต่อการบำรุงรักษา ในท้ายที่สุดพวกเขาทั้งหมดเป็นทางออกที่ดีสำหรับรูปแบบที่แตกต่างกันของคำถาม . . ทุกอย่างจะขึ้นอยู่กับความสำคัญของสถานการณ์ของคุณ
talemyn


5

ตัวเลือก ES6 ที่ยอดเยี่ยมคือpadStartสตริงที่ว่างเปล่า แบบนี้:

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

หมายเหตุ: สิ่งนี้จะไม่ทำงานใน IE (โดยไม่ต้องใส่ polyfill)


3
มีเหตุผลใดที่คุณจะแนะนำวิธี ES6 นี้กับอีกวิธีหนึ่งs = '#'.repeat(10)จาก @ user4227915 จากคำตอบข้างต้น?
talemyn

@talemyn Simpler ไวยากรณ์
Mendy

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

คุณยังสามารถเพิ่ม 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;
      }
    } 

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

โปรดเพิ่มคำอธิบายเพิ่มเติมลงในคำตอบของคุณเนื่องจากข้อมูลโค้ดนั้นไม่ได้ให้คำตอบ
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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.