Có cách nào dễ dàng để trả về một chuỗi lặp lại X số lần không?


318

Tôi đang cố gắng chèn một số vết lõm nhất định trước một chuỗi dựa trên độ sâu của vật phẩm và tôi tự hỏi liệu có cách nào để trả về chuỗi lặp lại X lần không. Thí dụ:

string indent = "---";
Console.WriteLine(indent.Repeat(0)); //would print nothing.
Console.WriteLine(indent.Repeat(1)); //would print "---".
Console.WriteLine(indent.Repeat(2)); //would print "------".
Console.WriteLine(indent.Repeat(3)); //would print "---------".

9
Không chắc chắn nếu điều này có thể áp dụng được, nhưng bạn cũng có thể muốn xem IndentsTextWriter .
Chris hét lên

Bạn có muốn xem xét thay đổi câu trả lời được chấp nhận vì câu hỏi của bạn là về sự lặp lại của chuỗi và không phải là ký tự mà câu trả lời được chấp nhận mô tả? Cho đến ngày hôm nay cho đến .Net v4.7, bất kỳ hàm tạo nào bị quá tải của Stringlớp không lấy một chuỗi làm tham số để tạo ra sự lặp lại từ đó có thể khiến câu trả lời được chấp nhận trở nên hoàn hảo.
RBT

Câu trả lời:


538

Nếu bạn chỉ có ý định lặp lại cùng một ký tự, bạn có thể sử dụng hàm tạo chuỗi chấp nhận một char và số lần lặp lại nónew String(char c, int count) .

Ví dụ: để lặp lại dấu gạch ngang năm lần:

string result = new String('-', 5);
Output: -----

8
Cảm ơn đã nhắc nhở tôi về tính năng nhỏ xinh này. Tôi nghĩ rằng nó đã bị mất trong góc của tâm trí của tôi.
Chris hét lên

3
Vì tab metacharacter '\ t' là một char nên nó cũng hoạt động để thụt lề.
cori

91
Đây là một mẹo rất hữu ích của C #, nhưng tiêu đề của câu hỏi là hỏi về một chuỗi (không phải là char). Các câu trả lời khác bên dưới câu hỏi này thực sự đang trả lời câu hỏi, nhưng được đánh giá thấp hơn nhiều. Tôi không cố gắng không tôn trọng câu trả lời của Ahmad, nhưng tôi nghĩ rằng tiêu đề của câu hỏi này nên được thay đổi (nếu câu hỏi thực sự liên quan đến các nhân vật) hoặc các câu trả lời khác thực sự nên được nêu lên (và không phải câu hỏi này).
pghprogrammer4

14
@Ahmad Như tôi đã nói, tôi không downvote vì tôi không nghĩ bạn đã cung cấp thông tin tốt, nhưng vì thông tin bạn cung cấp không liên quan đến việc trả lời câu hỏi như đã nêu . Hãy tưởng tượng nếu bạn đang tìm cách lặp lại chuỗi (không phải ký tự) và khi bạn nhận được câu hỏi có liên quan, bạn phải cuộn qua một số mẹo 'hữu ích' để có câu trả lời thực sự cho câu hỏi. Nếu downvote là xúc phạm bạn, tôi có thể loại bỏ nó. Nhưng bạn có thấy tôi đến từ đâu không? Tôi hoàn toàn không có cơ sở ở đây?
pghprogrammer4

11
@ pghprogrammer4 IMHO, downvote có thể khá nản lòng và chỉ nên được sử dụng cho các câu trả lời có hại / gây hiểu lầm / thật sự, cần một thay đổi lớn hoặc nên bị xóa bởi tác giả của chúng. Câu trả lời tồn tại bởi vì mọi người rất hào phóng và muốn chia sẻ những gì họ biết. Nói chung, các trang web này thực sự khuyến khích upvote để đưa câu trả lời hữu ích lên đầu.
ToolmakerSteve

271

Nếu bạn đang sử dụng .NET 4.0, bạn có thể sử dụng string.Concatcùng với Enumerable.Repeat.

int N = 5; // or whatever
Console.WriteLine(string.Concat(Enumerable.Repeat(indent, N)));

Nếu không, tôi sẽ đi với một cái gì đó giống như câu trả lời của Adam .

Lý do tôi thường không khuyên bạn nên sử dụng câu trả lời của Andrey chỉ đơn giản là ToArray()cuộc gọi giới thiệu quá mức không cần thiết với StringBuildercách tiếp cận được đề xuất bởi Adam. Điều đó nói rằng, ít nhất là nó hoạt động mà không yêu cầu .NET 4.0; và nó nhanh chóng và dễ dàng (và sẽ không giết bạn nếu hiệu quả không quá đáng lo ngại).


3
Điều này sẽ hoạt động độc đáo với các chuỗi - như nếu bạn cần nối các khoảng trắng không phá vỡ (& nbsp;). Nhưng tôi cho rằng hàm tạo chuỗi sẽ nhanh nhất nếu bạn giao dịch với char ...
woodbase

1
Chuỗi constructor sẽ chỉ làm việc cho một char. để tùy chọn sử dụng Concat Lặp lại sẽ hoạt động cho chuỗi
Eli Dagan

4
Cảm ơn đã trả lời câu hỏi tiêu đề thực tế!
Mark K Cowan

Tôi thích câu trả lời này!
Ji_in_coding

Nếu bạn đang nhận -System.Linq.Enumerable vv làm đầu ra, thì đó là vì bạn (ok, đây là tôi) đã quá nhanh để sao chép / dán và sửa đổi đoạn trích. Nếu bạn cần nối một chuỗi khác vào đầu ra của Enumerable.Repeat, bạn cần làm như thế này: Console.WriteLine(string.Concat("-", string.Concat(Enumerable.Repeat(indent, N))));
Gabe

47
public static class StringExtensions
{
    public static string Repeat(this string input, int count)
    {
        if (!string.IsNullOrEmpty(input))
        {
            StringBuilder builder = new StringBuilder(input.Length * count);

            for(int i = 0; i < count; i++) builder.Append(input);

            return builder.ToString();
        }

        return string.Empty;
    }
}

6
Bạn có thể chuyển input.Length * countcho nhà StringBuilderxây dựng không, bạn nghĩ sao?
Dan Tao

Và nếu bạn chuyển input.Length * countđến hàm StringBuildertạo, bạn có thể bỏ qua StringBuilderhoàn toàn và tạo một char [] có kích thước phù hợp ngay lập tức.
dtb

@dtb: Tôi tò mò tại sao bạn muốn làm điều đó. Tôi không thể tưởng tượng rằng nó sẽ nhanh hơn nhiều (nếu có) so với việc sử dụng a StringBuildervà mã sẽ kém minh bạch hơn.
Adam Robinson

@dtb: yuck. Sử dụng StringBuilder; nó được thiết kế để làm điều này một cách hiệu quả.
ToolmakerSteve

Adam, tôi thấy bạn đã gặp rắc rối khi kiểm tra đầu vào cho null khi thêm nó vào đếm, nhưng sau đó cho phép điều đó xảy ra, dựa vào Append để không làm gì cho null. IMHO điều này ít hơn rõ ràng: nếu null là một đầu vào có thể, tại sao không kiểm tra trước đó và trả về một chuỗi trống?
ToolmakerSteve

46

giải pháp hiệu quả nhất cho chuỗi

string result = new StringBuilder().Insert(0, "---", 5).ToString();

1
Chắc chắn là một lót đẹp. Chắc chắn không phải là người thực hiện nhất. StringBuilder có một chút chi phí so với số lượng kết nối rất ít.
Teejay

25

Đối với nhiều kịch bản, đây có lẽ là giải pháp gọn gàng nhất:

public static class StringExtensions
{
    public static string Repeat(this string s, int n)
        => new StringBuilder(s.Length * n).Insert(0, s, n).ToString();
}

Cách sử dụng là:

text = "Hello World! ".Repeat(5);

Điều này dựa trên các câu trả lời khác (đặc biệt là @ c0rd's). Cũng như sự đơn giản, nó có các tính năng sau, mà không phải tất cả các kỹ thuật khác được thảo luận đều chia sẻ:

  • Sự lặp lại của một chuỗi có độ dài bất kỳ, không chỉ là một ký tự (theo yêu cầu của OP).
  • Sử dụng hiệu quả StringBuilderthông qua lưu trữ preallocation.

Tôi đồng ý, điều này thật tuyệt vời. Tôi vừa thêm mã này vào mã của mình bằng tín dụng cho Bob! Cảm ơn!
John Burley

22

Sử dụng String.PadLeft , nếu chuỗi mong muốn của bạn chỉ chứa một char duy nhất.

public static string Indent(int count, char pad)
{
    return String.Empty.PadLeft(count, pad);
}

Tín dụng do ở đây


1
HÔN. Chúng ta cần StringBuilders và tiện ích mở rộng để làm gì? Đây là một vấn đề rất đơn giản.
DOK

1
Tôi không biết, điều này dường như để giải quyết vấn đề như phrased với một số thanh lịch. Và btw, bạn đang gọi ai là 'S'? :-)
Steve Townsend

7
Nhưng đây không thực sự chỉ là một phiên bản ít rõ ràng hơn của hàm stringtạo có một charvà mộtint ?
Dan Tao

Nó sẽ trông đẹp hơn với String.Empty thay vì "" ... nếu không, giải pháp tốt;)
Thomas Levesque

@Steve BTW các String.PadLeftđối số được đảo ngược. Việc countđến trước nhân vật đệm.
Ahmad Mageed

17

Bạn có thể lặp lại chuỗi của mình (trong trường hợp đó không phải là một ký tự đơn) và nối kết quả, như sau:

String.Concat(Enumerable.Repeat("---", 5))

12

Tôi sẽ đi tìm câu trả lời của Dan Tao, nhưng nếu bạn không sử dụng .NET 4.0, bạn có thể làm một cái gì đó như thế:

public static string Repeat(this string str, int count)
{
    return Enumerable.Repeat(str, count)
                     .Aggregate(
                        new StringBuilder(),
                        (sb, s) => sb.Append(s))
                     .ToString();
}

3
Nếu tôi tìm thấy đoạn trích trong dự án của mình, tôi sẽ tự hỏi ai đã vi phạm KISS và tại sao ... tốt đẹp khác
Noctis

4
        string indent = "---";
        string n = string.Concat(Enumerable.Repeat(indent, 1).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 2).ToArray());
        string n = string.Concat(Enumerable.Repeat(indent, 3).ToArray());

1
@Adam: Tôi đoán bạn cần phải làm điều đó trước .NET 4.0.
Dan Tao

3

Tôi thích câu trả lời được đưa ra. Dọc theo những dòng tội lỗi là những gì tôi đã sử dụng trong quá khứ:

"" .PadLeft (3 * thụt lề, '-')

Điều này sẽ hoàn thành việc tạo ra một thụt lề nhưng về mặt kỹ thuật, câu hỏi là lặp lại một chuỗi. Nếu chuỗi thụt lề là một cái gì đó như> - <thì điều này cũng như câu trả lời được chấp nhận sẽ không hoạt động. Trong trường hợp này, giải pháp của c0rd sử dụng Stringbuilder có vẻ tốt, mặc dù chi phí hoạt động của trình tạo chuỗi trên thực tế có thể không làm cho nó trở nên hiệu quả nhất. Một tùy chọn là xây dựng một chuỗi các chuỗi, điền nó với các chuỗi thụt lề, sau đó nối chuỗi đó. Để trắng:

int Indent = 2;

string[] sarray = new string[6];  //assuming max of 6 levels of indent, 0 based

for (int iter = 0; iter < 6; iter++)
{
    //using c0rd's stringbuilder concept, insert ABC as the indent characters to demonstrate any string can be used
    sarray[iter] = new StringBuilder().Insert(0, "ABC", iter).ToString();
}

Console.WriteLine(sarray[Indent] +"blah");  //now pretend to output some indented line

Tất cả chúng ta đều yêu thích một giải pháp thông minh nhưng đôi khi đơn giản là tốt nhất.


3

Thêm Phương thức mở rộng Tôi đang sử dụng trên tất cả các dự án của mình:

public static string Repeat(this string text, int count)
{
    if (!String.IsNullOrEmpty(text))
    {
        return String.Concat(Enumerable.Repeat(text, count));
    }
    return "";
}

Hy vọng ai đó có thể sử dụng nó ...


2

Ngạc nhiên không ai đi học cũ. Tôi không đưa ra bất kỳ khiếu nại nào về mã này, nhưng chỉ để cho vui:

public static string Repeat(this string @this, int count)
{
    var dest = new char[@this.Length * count];
    for (int i = 0; i < dest.Length; i += 1)
    {
        dest[i] = @this[i % @this.Length];
    }
    return new string(dest);
}

Rõ ràng là tôi đã để nó như một bài kiểm tra cho người đọc sắc sảo :) Rất sắc sảo, cảm ơn.
OlduwanSteve

1
Không có gì cũ về việc đặt tên một tham số @this, đó luôn là một ý tưởng khủng khiếp :)
Dave Jellison

2
Tôi không thích sử dụng từ khóa làm tên biến trừ khi bị ép buộc (chẳng hạn như @ class = "cái gì đó" khi làm việc với MVC vì bạn cần lớp tham khảo CSS nhưng đó là từ khóa trong C # (dĩ nhiên). Đó là một quy tắc chung. Mặc dù đó chắc chắn là mã có thể biên dịch được và hợp pháp, hãy nghĩ về việc dễ đọc và gõ, cả hai lý do thực tế. Tôi rất thích sử dụng tên tham số để mô tả những gì xảy ra trước vì vậy Lặp lại (chuỗi hạt này, int đếm) có thể là imho minh họa hơn.
Dave Jellison

1
Thú vị, cảm ơn. Tôi nghĩ trong trường hợp này có lẽ bạn đúng rằng @this ít mô tả hơn nó có thể. Tuy nhiên, nói chung tôi nghĩ khá phổ biến là mở rộng các lớp hoặc giao diện trong đó tên hợp lý duy nhất cho 'cái này' là khá chung chung. Nếu bạn có một tham số gọi là 'dụ' hoặc 'nó' hoặc 'str' (xem MSDN ) thì điều bạn có thể có nghĩa là 'cái này'.
OlduwanSteve 7/11/13

1
Về cơ bản, tôi đồng ý với bạn, nhưng vì lý do tranh luận ... vì tôi biết nhiều hơn về chuỗi tôi đang xây dựng nên tôi có thể thực hiện công việc tốt hơn một chút so với StringBuilder. StringBuilder phải đoán khi phân bổ bộ nhớ. Được cho là không có vấn đề gì trong nhiều tình huống, nhưng ai đó ngoài kia có thể đang xây dựng một số lượng lớn các chuỗi lặp lại song song và vui mừng khi có được một vài chu kỳ đồng hồ trở lại :)
OlduwanSteve 18/03/2016

2

Không chắc cách thức này sẽ thực hiện, nhưng nó là một đoạn mã dễ dàng. (Tôi có lẽ đã làm cho nó xuất hiện phức tạp hơn nó.)

int indentCount = 3;
string indent = "---";
string stringToBeIndented = "Blah";
// Need dummy char NOT in stringToBeIndented - vertical tab, anyone?
char dummy = '\v';
stringToBeIndented.PadLeft(stringToBeIndented.Length + indentCount, dummy).Replace(dummy.ToString(), indent);

Ngoài ra, nếu bạn biết số cấp tối đa bạn có thể mong đợi, bạn có thể chỉ cần khai báo một mảng và lập chỉ mục vào đó. Bạn có thể muốn làm cho mảng này tĩnh hoặc hằng.

string[] indents = new string[4] { "", indent, indent.Replace("-", "--"), indent.Replace("-", "---"), indent.Replace("-", "----") };
output = indents[indentCount] + stringToBeIndented;      

2

Tôi không có đủ đại diện để bình luận về câu trả lời của Adam, nhưng cách tốt nhất để làm điều đó là như thế này:

public static string RepeatString(string content, int numTimes) {
        if(!string.IsNullOrEmpty(content) && numTimes > 0) {
            StringBuilder builder = new StringBuilder(content.Length * numTimes);

            for(int i = 0; i < numTimes; i++) builder.Append(content);

            return builder.ToString();
        }

        return string.Empty;
    }

Bạn phải kiểm tra xem numTimes có lớn hơn không, nếu không bạn sẽ có ngoại lệ.


2

Tôi đã không thấy giải pháp này. Tôi thấy đơn giản hơn cho nơi tôi hiện đang phát triển phần mềm:

public static void PrintFigure(int shapeSize)
{
    string figure = "\\/";
    for (int loopTwo = 1; loopTwo <= shapeSize - 1; loopTwo++)
    {
        Console.Write($"{figure}");
    }
}

2

Để sử dụng chung, các giải pháp liên quan đến lớp StringBuilder là tốt nhất để lặp lại các chuỗi nhiều ký tự. Nó được tối ưu hóa để xử lý sự kết hợp của một số lượng lớn các chuỗi theo cách mà việc nối đơn giản không thể và điều đó sẽ khó hoặc không thể thực hiện hiệu quả hơn bằng tay. Các giải pháp StringBuilder hiển thị ở đây sử dụng các lần lặp O (N) để hoàn thành, tỷ lệ cố định tỷ lệ với số lần lặp lại.

Tuy nhiên, đối với số lần lặp lại rất lớn hoặc ở mức độ hiệu quả cao phải được vắt kiệt, cách tiếp cận tốt hơn là làm một cái gì đó tương tự như chức năng cơ bản của StringBuilder nhưng để tạo ra các bản sao bổ sung từ đích, thay vì từ chuỗi gốc, như sau.

    public static string Repeat_CharArray_LogN(this string str, int times)
    {
        int limit = (int)Math.Log(times, 2);
        char[] buffer = new char[str.Length * times];
        int width = str.Length;
        Array.Copy(str.ToCharArray(), buffer, width);

        for (int index = 0; index < limit; index++)
        {
            Array.Copy(buffer, 0, buffer, width, width);
            width *= 2;
        }
        Array.Copy(buffer, 0, buffer, width, str.Length * times - width);

        return new string(buffer);
    }

Điều này làm tăng gấp đôi độ dài của chuỗi nguồn / đích với mỗi lần lặp, giúp tiết kiệm chi phí đặt lại bộ đếm mỗi lần nó đi qua chuỗi ban đầu, thay vào đó đọc trơn tru và sao chép chuỗi dài hơn nhiều, điều mà các bộ xử lý hiện đại có thể làm được nhiều hiệu quả hơn.

Nó sử dụng logarit cơ sở 2 để tìm số lần cần gấp đôi độ dài của chuỗi và sau đó tiến hành làm như vậy nhiều lần. Vì phần còn lại sẽ được sao chép ít hơn tổng chiều dài mà nó được sao chép, nên sau đó có thể chỉ cần sao chép một tập hợp con của những gì nó đã tạo.

Tôi đã sử dụng phương thức Array.Copy () qua việc sử dụng StringBuilder, vì việc sao chép nội dung của StringBuilder vào chính nó sẽ có chi phí sản xuất một chuỗi mới với nội dung đó với mỗi lần lặp. Array.Copy () tránh điều này, trong khi vẫn hoạt động với hiệu suất cực kỳ cao.

Giải pháp này cần hoàn thành các lần lặp O (1 + log N) , tốc độ tăng logarit với số lần lặp lại (nhân đôi số lần lặp lại bằng một lần lặp bổ sung), tiết kiệm đáng kể so với các phương pháp khác, tăng tỷ lệ thuận.


1

Một cách khác là để xem xét stringnhư IEnumerable<char>và có một phương pháp khuyến nông chung chung mà sẽ nhân lên các mục trong một bộ sưu tập của các yếu tố cụ thể.

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}

Vì vậy, trong trường hợp của bạn:

string indent = "---";
var f = string.Concat(indent.Repeat(0)); //.NET 4 required
//or
var g = new string(indent.Repeat(5).ToArray());

1

In một dòng với sự lặp lại.

Console.Write(new string('=', 30) + "\n");

==============================


Tại sao bạn không sử dụng Console.WriteLine thay vì nối thêm \ n ở cuối chuỗi?
InxaneNinja

-1

Bạn có thể tạo một ExtensionMethod để làm điều đó!

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    string ret = "";

    for (var x = 0; x < count; x++)
    {
      ret += str;
    }

    return ret;
  }
}

Hoặc sử dụng giải pháp @Dan Tao:

public static class StringExtension
{
  public static string Repeat(this string str, int count)
  {
    if (count == 0)
      return "";

    return string.Concat(Enumerable.Repeat(indent, N))
  }
}

3
Xem nhận xét của tôi về câu trả lời của Kyle
Thomas Levesque
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.