2010-12-15 5 views
1

Je me demandais si vous pouviez me dire quel serait le moyen le plus efficace de répéter une chaîne. J'ai besoin de créer une chaîne 33554432 octets long, en répétant la chaîne "Bonjour, monde" jusqu'à ce qu'il remplisse ce tampon. Quelle est la meilleure façon de le faire, C est facile dans ce cas:traduction du code: répétition d'une chaîne jusqu'à un maximum

for (i = 0; i < BIGSTRINGLEN - step; i += step) 
     memcpy(bigstring+i, *s, step); 

Merci.

+2

Considérez-vous 1 caractère == 1 octet? Parce que pour le codage ASCII pur est correct, mais pour d'autres codages, il pourrait être faux ... – digEmAll

Répondre

3

Un moyen efficace serait d'utiliser un StringBuilder:

string text = "hello, world"; 
StringBuilder builder = new StringBuilder(BIGSTRINGLEN); 
while (builder.Length + text.Length <= BIGSTRINGLEN) { 
    builder.Append(text); 
} 
string result = builder.ToString(); 
+4

Il sera encore plus efficace si vous initialisez StringBuilder avec la longueur désirée: new StringBuilder (BIGSTRINGLEN); – codymanix

+0

@codymanix, vous avez absolument raison, réponse mise à jour. Merci :) –

+0

+1 pour poster presque exactement la même réponse que je viens de poster! – wageoghe

1

Je ne sais pas si c'est la façon la plus efficace, mais si vous utilisez .NET 3.5 ou plus tard, cela pourrait fonctionner:

String.Join("", System.Linq.Enumerable.Repeat("hello, world", 2796203).ToArray()).Substring(0, 33554432); 

Si la longueur que vous voulez est dynamique, vous pouvez remplacer certains des nombres codés en dur par des calculs simples.

+0

Hm ... Je suis sur Mono, pas LinQ. Mise à jour des tags en conséquence. Merci. –

+0

Pas de Linq? Triste! Je voudrais regarder à la réponse de Frédéric alors. Peu importe ce que vous faites, vous devriez certainement utiliser StringBuilder plutôt que la concaténation de chaînes si vous travaillez avec de grandes chaînes. –

+0

Vous savez que l'appel ToArray() crée un tableau avec 2796203 chaînes, vous (je sais que c'est nécessaire pour String.Join). Sans ce ToArray(), votre méthode aurait à peu près les mêmes performances que StringBuilder, puisque String.Join utilise en interne StringBuilder, la surcharge pour l'énumérateur est minime. – codymanix

2

D'abord, voulez-vous la chaîne à 33554432 octets ou caractères? .NET et C# utilisent des caractères de 16 bits, donc ils ne sont pas équivalents.

Si vous voulez 33554432 caractères, la solution naïve serait la concaténation de chaîne. Voir la réponse de Frédéric Hamidi.

Si vous voulez octets, vous aurez besoin de faire quelque chose d'un peu plus intéressant:

int targetLength = 33554432; 
string filler = "hello, world"; 
byte[] target = new byte[targetLength]; 

// Convert filler to bytes. Can use other encodings here. 
// I am using ASCII to match C++ output. 
byte[] fillerBytes = Encoding.ASCII.GetBytes(filler); 
//byte[] fillerBytes = Encoding.Unicode.GetBytes(filler); 
//byte[] fillerBytes = Encoding.UTF8.GetBytes(filler); 

int position = 0; 
while((position + fillerBytes.Length) < target.Length) 
{ 
    fillerBytes.CopyTo(target, position); 
    position += fillerBytes.Length; 
} 

// At this point, need to possibly do a partial copy. 
if (position < target.Length) 
{ 
    int bytesNecessary = target.Length - position; 
    Array.Copy(fillerBytes, 0, target, position, bytesNecessary); 
} 
+2

J'ai essayé ceci ... chaîne de concat a pris pour toujours ... stringbuilder était 232ms ... –

+0

depuis l'OP mentionné l'efficacité, je ne pense pas qu'il est approprié de donner la concaténation de chaînes comme exemple même si vous mentionnez que c'est une implémentation naïve. +1 au reste de la réponse. – Davy8

+0

Oui ... J'ai oublié 'StringBuilder', puisque Java convertit maintenant pour l'utiliser automatiquement. J'ai modifié ma réponse de manière appropriée. – jdmichal

0

Qu'en est-ce? Définissez StringBuilder à la taille maximale attendue, puis ajoutez la chaîne souhaitée tant que l'ajout d'une autre chaîne ne dépasse pas la taille maximale souhaitée.

StringBuilder sb = new StringBuilder(33554432); 
    int max = sb.MaxCapacity; 
    String hello = "hello, world"; 

    while (sb.Length + hello.Length <= max) 
    { 
    sb.Append(hello); 
    } 

    string longString = sb.ToString(); 
0

Ceci évite une boucle qui ajoute de façon répétée la chaîne. Au lieu de cela, je "double" la corde jusqu'à ce qu'elle se rapproche de la bonne longueur et ensuite je mets les morceaux "doublés" ensemble de manière appropriée.

static string Repeat(string s, int length) { 
     if (length < s.Length) { 
      return s.Substring(0, length); 
     } 
     var list = new List<string>(); 

     StringBuilder t = new StringBuilder(s); 
     do { 
      string temp = t.ToString(); 
      list.Add(temp); 
      t.Append(temp); 
     } while(t.Length < length); 

     int index = list.Count - 1; 
     StringBuilder sb = new StringBuilder(length); 
     while (sb.Length < length) { 
      while (list[index].Length > length) { 
       index--; 
      } 
      if (list[index].Length <= length - sb.Length) { 
       sb.Append(list[index]); 
      } 
      else { 
       sb.Append(list[index].Substring(0, length - sb.Length)); 
      } 
     } 
     return sb.ToString(); 

    } 

Ainsi, par exemple, sur l'entrée (« Bonjour, monde! », 64), nous construisons les chaînes

13: Hello, World! 
26: Hello, World!Hello, World! 
52: Hello, World!Hello, World!Hello, World!Hello, World! 

Ensuite, nous construirions le résultat par concaténer la chaîne de longueur 52 à la Je sous -signe la longueur 12 de la chaîne de longueur 13.

Je suppose, bien sûr, que par octets, vous vouliez dire longueur. Sinon, vous pouvez facilement modifier les encodages ci-dessus en utilisant ce que vous voulez en termes d'octets.

+0

Donne-moi: Temps utilisé (float): 315.9855 ms, stringbuilder est toujours le meilleur ... mais je comprends votre point. –

+0

Un test sur une entrée ne vous dira rien. – jason

+0

sauf si votre univers est juste cette chaîne, et les nombres doublent, dans ce cas, il vous dit tout ce que vous voulez savoir! –

Questions connexes