Posso "moltiplicare" una stringa (in C #)?


136

Supponiamo che io abbia una stringa, ad esempio,

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

Voglio sostanzialmente scriverlo più volte, a seconda del valore intero.

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

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

EDIT: So che posso facilmente scrivere la mia funzione per implementare questo, mi stavo solo chiedendo se ci fosse un operatore di stringa strano che non sapevo


Risposte:


222

In .NET 4 puoi farlo:

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

9
E non è molto più in .NET 3.5: String.Concat (Enumerable.Repeat ("Hello", 4) .ToArray ())
Mark Foreman

4
Non credo sia affatto elegante. In Python il codice per farlo è: snip * moltiplicatore (non è orribile .. ma nemmeno bello).
Demented Hedgehog

7
@dementedhedgehog So che riconosci la tua demenza, ma anche soffrendo mentre fai, potresti essere in grado di vedere che un esempio di Python non avrebbe fatto un'ottima risposta a una domanda C # ... Penso che molti di noi possano vedere che la selezione della lingua è sempre un compromesso e praticamente qualsiasi risposta a qualsiasi domanda potrebbe essere annotata con il patrocinio, a favore o contro.
Will Dean il

1
@will dean: mi riferivo alla dichiarazione di Matthew Nichols sull'eleganza del codice che hai lì. Per quanto ne so, il tuo codice è elegante per C #, così come è attualmente, per questo problema. Il punto che sto cercando di chiarire è: (credo) sarebbe molto semplice (per microsoft, poiché le stringhe sono sigillate) estendere C # per sovraccaricare l'operatore * per consentire la moltiplicazione di int *. Che sarebbe quindi elegante in un certo senso universale, imho, non solo elegante nel contesto dei vincoli imposti da C # come esiste al momento.
Demented Hedgehog

@dementedhedgehog Per me, questo va contro ciò che operator*rappresenta il binario . A ciascuno il suo, immagino.
TEK,

99

Nota che se la tua "stringa" è solo un singolo carattere, c'è un sovraccarico del costruttore di stringhe per gestirlo:

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

Questo è davvero professionale.
Zaven Zareyan,

61

Sfortunatamente / per fortuna, la classe di stringhe è sigillata, quindi non puoi ereditarla e sovraccaricare l'operatore *. Puoi creare un metodo di estensione però:

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
Proprio dove stavo andando! Probabilmente potresti ottimizzare utilizzando il moltiplicatore source.Length * nel ctor StringBuilder
Marc Gravell

2
Il commento di Marc era proprio dove stavo andando :)
Jon Skeet,

1
Hai bisogno di (source.Length * moltiplicatore), non solo (moltiplicatore)
Marc Gravell

1
Molto sicuro. Alloca una stringa (di quella lunghezza) dietro le quinte, quindi la muta. Non funziona come un normale Elenco <T> ecc.
Marc Gravell

1
Il metodo di estensione è l'ideale qui.
Chris Ballance,

12

Sono con DrJokepu su questo , ma se per qualche motivo volessi imbrogliare usando la funzionalità integrata, potresti fare qualcosa del genere:

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

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

Oppure, se si utilizza .NET 4:

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

Personalmente non mi preoccuperei però: un metodo di estensione personalizzato è molto più bello.


1
Non ho mai saputo che ci fosse un imbroglione come questo. =)
Jronny,

10

Solo per completezza: ecco un altro modo per farlo:

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

Penso di averlo estratto da Stack Overflow qualche tempo fa, quindi non è una mia idea.


9

Dovresti scrivere un metodo - ovviamente, con C # 3.0 potrebbe essere un metodo di estensione:

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

poi:

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

.NET3 non aveva nemmeno Enumerable.Repeat?
Will Dean,

@Will - .NET 3 era WCF / WPF ecc., Quindi no; esiste in .NET 3.5, ma allora dovresti averne bisogno anche string.Jointu - perché non limitarti a ripetere n volte? Molto più diretto.
Marc Gravell

Grazie - Non stavo pensando correttamente a 3.0 contro 3.5. Quanto al perché non usare solo un ciclo, questa è sicuramente l'essenza del dibattito funzionale vs imperativo? Ho pubblicato una risposta .net 4 più in basso, che penso non sia poi così male nel dibattito sulla "intelligenza funzionale" vs "ovvietà in loop".
Will Dean,

8

Un po 'in ritardo (e solo per divertimento), se vuoi davvero usare l' *operatore per questo lavoro, puoi farlo:

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

E così:

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

Si noti che, finché si è in grado di trovare un comportamento ragionevole per loro, è possibile gestire anche altri operatori attraverso la StringWrapclasse, come \, ^,% ecc ...

PS:

Multiply()crediti di estensione a @DrJokepu tutti i diritti riservati ;-)


7

Questo è molto più conciso:

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

Lo spazio dei nomi using System.Text;dovrebbe essere importato in questo caso.


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

Se hai .Net 3.5 ma non 4.0, puoi usare System.Linq's

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

Per ottenere una singola stringa avresti ancora bisogno String.Concat, e su 3.5 avresti anche bisogno .ToArray(). Non ho la soluzione più elegante, temo.
Kobi,

2

Dato che tutti stanno aggiungendo i propri esempi .NET4 / Linq, potrei anche aggiungere i miei. (Fondamentalmente, è DrJokepu, ridotto a un liner)

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

Ok, ecco la mia opinione sulla questione:

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

Ovviamente sono un po 'sciocco, ma quando ho bisogno di avere tabulazioni nelle classi che generano codice, Enumerable.Repeat lo fa per me. E sì, anche la versione StringBuilder va bene.


0

Ecco la mia opinione su questo solo per riferimento futuro:

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

Spero che tu non lo usi davvero ParallelEnumerablein situazioni come questa. string.Joindeve usare gli elementi in ordine, quindi parallelizzare la loro generazione non è richiesto.
Gabe,

@Gabe: Dal momento che gli articoli sono gli stessi e in realtà sono solo copie di thisString, non c'è bisogno di preoccuparsi dell'ordinamento qui, immagino.
Jronny,

Concordo con molti insegnanti del settore sul fatto che di solito è bene codificare per dire cosa intendi. Non vi è alcun vantaggio nel dire che volete questo parallelo e pensate solo segretamente "Beh, so che non sarà parallelo in questo caso particolare"
vedi il

Penso che renderlo parallelo lo renda più veloce, o per favore illuminami. Ecco perché sto convertendo questo in ParallelEnumerable, quindi penso di codificare per dire cosa intendo ... Grazie.
Jronny,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.