ฉันสามารถ "คูณ" สตริง (ใน C #)?


136

สมมติว่าฉันมีสตริงตัวอย่างเช่น

string snip =  "</li></ul>";

ฉันต้องการเขียนหลายครั้งขึ้นอยู่กับค่าจำนวนเต็ม

string snip =  "</li></ul>";
int multiplier = 2;

// TODO: magic code to do this 
// snip * multiplier = "</li></ul></li></ul>";

แก้ไข: ฉันรู้ว่าฉันสามารถเขียนฟังก์ชั่นของตัวเองเพื่อนำไปใช้งานได้ง่ายฉันแค่สงสัยว่ามีตัวดำเนินการสตริงแปลก ๆ ที่ฉันไม่รู้


คำตอบ:


222

ใน. NET 4 คุณสามารถทำได้:

String.Concat(Enumerable.Repeat("Hello", 4))

9
และมันก็ไม่ได้มากขึ้นใน. NET 3.5: String.Concat (Enumerable.Repeat ("Hello", 4) .ToArray ())
Mark Foreman

4
ฉันไม่คิดว่ามันจะหรูหราอะไร ในไพ ธ อนรหัสที่ต้องทำคือ: snip * ตัวคูณ (มันไม่น่ากลัว .. แต่มันก็ไม่สวยเลย)
เฮดจ์ฮอก

7
@dementhedgehog ฉันรู้ว่าคุณรับรู้ภาวะสมองเสื่อมของคุณเอง แต่ถึงแม้จะทุกข์ทรมานอย่างที่คุณทำคุณอาจเห็นว่าตัวอย่างของ Python จะไม่ได้รับคำตอบที่ดีสำหรับคำถาม C # ... ฉันคิดว่าพวกเราส่วนใหญ่เห็น การเลือกภาษานั้นเป็นสิ่งที่ประนีประนอมอยู่เสมอและคำตอบสำหรับคำถามใด ๆ ก็อาจถูกเชิงอรรถด้วยการสนับสนุนไม่ว่าจะเพื่อหรือต่อต้าน
Will Dean

1
@ จะเป็นคณบดี: ฉันแค่อ้างถึงคำสั่งของ Matthew Nichols เกี่ยวกับความงดงามของรหัสที่คุณมี เท่าที่ฉันสามารถบอกได้ว่ารหัสของคุณนั้นสง่างามสำหรับ C # ซึ่งในขณะนี้มันยืนสำหรับปัญหานี้ จุดที่ฉันพยายามทำคือ: (ฉันเชื่อ) มันจะง่ายมาก (สำหรับ microsoft เนื่องจากมีการปิดผนึกสตริง) เพื่อขยาย C # เพื่อโอเวอร์โหลดตัวดำเนินการ * เพื่ออนุญาตการคูณสตริง int * ซึ่งอันที่จริงแล้วจะสง่างามในความรู้สึกสากลบาง imho ไม่เพียง แต่สง่างามในบริบทของข้อ จำกัด ที่กำหนดโดย C # ตามที่มีอยู่ในขณะนี้
เม่นลงมา

@dehegehedgehog สำหรับฉันที่ไปกับสิ่งที่operator*แสดงถึงไบนารี สำหรับแต่ละคนฉันคิดว่า
TEK

99

โปรดทราบว่าหาก "สตริง" ของคุณเป็นอักขระเดียวเท่านั้นจะมีตัวสร้างสตริงมากเกินไปที่จะจัดการ:

int multipler = 10;
string TenAs = new string ('A', multipler);

นี่เป็นมืออาชีพจริงๆ
Zaven Zareyan

61

น่าเสียดายที่ / โชคดีคลาสสตริงถูกปิดผนึกเพื่อให้คุณไม่สามารถสืบทอดจากมันได้ คุณสามารถสร้างวิธีการขยายแม้ว่า:

public static string Multiply(this string source, int multiplier)
{
   StringBuilder sb = new StringBuilder(multiplier * source.Length);
   for (int i = 0; i < multiplier; i++)
   {
       sb.Append(source);
   }

   return sb.ToString();
}

string s = "</li></ul>".Multiply(10);

5
ฉันกำลังจะไปไหน! คุณสามารถอาจจะเพิ่มประสิทธิภาพโดยใช้ source.Length * คูณใน ctor นั้น StringBuilder
Marc Gravell

2
ความคิดเห็นของมาร์คก็แค่ที่ผมกำลังจะ :)
จอนสกีต

1
คุณต้องการ (แหล่งที่มาความยาว * ตัวคูณ) ไม่ใช่แค่ (ตัวทวีคูณ)
Marc Gravell

1
แน่นอนมาก มันจัดสรรสตริง (ความยาวนั้น) ที่อยู่เบื้องหลังแล้วแปลงมัน มันใช้งานไม่ได้กับรายการปกติ <T> และอื่น ๆ
Marc Gravell

1
วิธีการขยายเหมาะอย่างยิ่งสำหรับที่นี่
Chris Ballance

12

ฉันใช้ DrJokepu กับอันนี้แต่ถ้าด้วยเหตุผลบางอย่างที่คุณต้องการโกงโดยใช้ฟังก์ชั่นในตัวคุณสามารถทำสิ่งนี้ได้:

string snip = "</li></ul>";
int multiplier = 2;

string result = string.Join(snip, new string[multiplier + 1]);

หรือถ้าคุณใช้. NET 4:

string result = string.Concat(Enumerable.Repeat(snip, multiplier));

โดยส่วนตัวฉันจะไม่รบกวน - วิธีการขยายที่กำหนดเองนั้นดีกว่ามาก


1
ฉันไม่เคยรู้ว่ามีการโกงเช่นนี้ =)
Jronny

10

เพื่อความสมบูรณ์ - นี่เป็นอีกวิธีหนึ่งในการทำสิ่งนี้:

public static string Repeat(this string s, int count)
{
    var _s = new System.Text.StringBuilder().Insert(0, s, count).ToString();
    return _s;
}

ฉันคิดว่าฉันดึงอันนั้นมาจาก Stack Overflow เมื่อไม่นานมานี้ดังนั้นจึงไม่ใช่ความคิดของฉัน


9

คุณต้องเขียนวิธี - แน่นอนด้วย C # 3.0 อาจเป็นวิธีการขยาย:

public static string Repeat(this string, int count) {
    /* StringBuilder etc */ }

แล้ว:

string bar = "abc";
string foo = bar.Repeat(2);

ไม่ได้. NET3 แม้แต่มี Enumerable ทำซ้ำ?
Will Dean

@ Will -. NET 3 คือ WCF / WPF ฯลฯ ดังนั้นไม่ มันมีอยู่ใน. NET 3.5 แต่ถ้าอย่างนั้นคุณก็ต้องใช้string.Joinมันเหมือนกัน - ทำไมไม่ลองวนซ้ำ n ล่ะ? ตรงมากขึ้น
Marc Gravell

ขอบคุณ - ฉันไม่ได้คิดอย่างถูกต้องเกี่ยวกับ 3.0 กับ 3.5 ทำไมถึงไม่ใช้แค่วนซ้ำนั่นคือสาระสำคัญทั้งหมดของการอภิปรายเชิงหน้าที่เทียบกับความจำเป็น? ฉันโพสต์คำตอบ. net 4 ต่ำลงซึ่งฉันคิดว่าไม่เลวเกินไปในการอภิปราย
Will Dean

8

สายเล็กน้อย (และเพื่อความสนุก) หากคุณต้องการใช้*โอเปอเรเตอร์สำหรับงานนี้จริงๆคุณสามารถทำสิ่งนี้ได้:

public class StringWrap
{
    private string value;
    public StringWrap(string v)
    {
        this.value = v;
    }
    public static string operator *(StringWrap s, int n)
    {
        return s.value.Multiply(n); // DrJokepu extension
    }
}

และอื่น ๆ :

var newStr = new StringWrap("TO_REPEAT") * 5;

โปรดทราบว่าตราบใดที่คุณมีความสามารถที่จะหาพฤติกรรมที่เหมาะสมสำหรับพวกเขานอกจากนี้คุณยังสามารถจัดการกับผู้ประกอบการอื่น ๆ ผ่านStringWrapระดับเช่น\, ^, %ฯลฯ ...

PS:

Multiply()ขยายเครดิตไปที่@DrJokepuสงวนลิขสิทธิ์ ;-)


7

นี่คือความรัดกุมมากขึ้น:

new StringBuilder().Insert(0, "</li></ul>", count).ToString()

เนมสเปซusing System.Text;ควรถูกนำเข้าในกรณีนี้


2
string Multiply(string input, int times)
{
     StringBuilder sb = new StringBuilder(input.length * times);
     for (int i = 0; i < times; i++)
     {
          sb.Append(input);
     }
     return sb.ToString();
}

2

หากคุณมี. Net 3.5 แต่ไม่ใช่ 4.0 คุณสามารถใช้ System.Linq's

String.Concat(Enumerable.Range(0, 4).Select(_ => "Hello").ToArray())

เพื่อให้ได้สายเดียวที่คุณจะยังคงต้องString.Concatและ 3.5 .ToArray()คุณควรที่จะยังจำเป็นที่จะต้อง ไม่ใช่ทางออกที่หรูหราที่สุดฉันกลัว
Kobi

2

เนื่องจากทุกคนกำลังเพิ่มตัวอย่าง. NET4 / Linq ของตัวเองฉันก็อาจจะเพิ่มของตัวเอง (โดยทั่วไปมันเป็นของ DrJokepu ลดเหลือหนึ่งซับ)

public static string Multiply(this string source, int multiplier) 
{ 
    return Enumerable.Range(1,multiplier)
             .Aggregate(new StringBuilder(multiplier*source.Length), 
                   (sb, n)=>sb.Append(source))
             .ToString();
}

0

ตกลงนี่เป็นเรื่องของฉันในเรื่อง:

public static class ExtensionMethods {
  public static string Multiply(this string text, int count)
  {
    return new string(Enumerable.Repeat(text, count)
      .SelectMany(s => s.ToCharArray()).ToArray());
  }
}

แน่นอนว่าฉันค่อนข้างโง่ แต่เมื่อฉันต้องมีตารางในคลาสที่สร้างรหัส Enumerable การทำซ้ำนั้นเหมาะกับฉัน ใช่รุ่น StringBuilder ก็ใช้ได้เช่นกัน


0

นี่คือสิ่งที่ฉันใช้สำหรับการอ้างอิงในอนาคต:

    /// <summary>
    /// Repeats a System.String instance by the number of times specified;
    /// Each copy of thisString is separated by a separator
    /// </summary>
    /// <param name="thisString">
    /// The current string to be repeated
    /// </param>
    /// <param name="separator">
    /// Separator in between copies of thisString
    /// </param>
    /// <param name="repeatTimes">
    /// The number of times thisString is repeated</param>
    /// <returns>
    /// A repeated copy of thisString by repeatTimes times 
    /// and separated by the separator
    /// </returns>
    public static string Repeat(this string thisString, string separator, int repeatTimes) {
        return string.Join(separator, ParallelEnumerable.Repeat(thisString, repeatTimes));
    }

ฉันหวังว่าคุณจะไม่ได้ใช้ParallelEnumerableในสถานการณ์เช่นนี้ string.Joinจำเป็นต้องใช้องค์ประกอบในการสั่งซื้อเพื่อให้ขนานรุ่นของพวกเขาจะไม่ถูกเรียกหา
Gabe

@Gabe: เนื่องจากไอเท็มเหมือนกันและเป็นเพียงสำเนาของสายนี้มันไม่จำเป็นต้องกังวลเกี่ยวกับการสั่งซื้อที่นี่ฉันเดา
Jronny

ฉันเห็นด้วยกับครูหลายคนในสาขาว่าปกติดีที่จะเขียนโค้ดเพื่อพูดในสิ่งที่คุณหมายถึง ไม่มีประโยชน์ที่จะบอกว่าคุณต้องการขนานนี้และเพียงแค่คิดว่า "ดีฉันรู้ว่ามันจะไม่ขนานในกรณีนี้ต่อไป"
sehe

ฉันคิดว่าการทำให้ขนานทำให้เร็วขึ้นหรือช่วยฉันด้วย นั่นเป็นสาเหตุที่ฉันแปลงค่านี้เป็น ParallelEnableable ดังนั้นฉันคิดว่าฉันโค้ดเพื่อพูดในสิ่งที่ฉันหมายถึง ... ขอบคุณ
Jronny
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.