Le titre est la question. Ci-dessous est ma tentative de réponse à travers la recherche. Mais je n'ai pas confiance en mon mal informés de recherche j'ai donc toujours se poser la question (Ce qui est le moyen le plus rapide pour parcourir les différents caractères dans une chaîne de caractères en C#?).
Parfois je veux faire défiler les caractères d'une chaîne de caractères un par un, comme lors de l'analyse de imbriquée jetons -- quelque chose qui ne peut être fait avec des expressions régulières. Je me demande ce que le moyen le plus rapide est de parcourir les différents caractères dans une chaîne, en particulier les très grandes chaînes.
J'ai fait un tas de tests moi-même et mes résultats sont ci-dessous. Cependant, il existe de nombreux lecteurs avec beaucoup plus de connaissance de la profondeur de l' .NET CLR et le compilateur C# donc je ne sais pas si je suis absent quelque chose d'évident, ou si j'ai fait une erreur dans mon code de test. Donc je sollicite votre réponse collective. Si quelqu'un a un aperçu de la façon dont la chaîne d'indexation fonctionne réellement, ce serait très utile. (Est-ce un C# langage compilé dans quelque chose d'autre derrière les coulisses? Ou quelque chose de construit dans le CLR?).
La première méthode à l'aide d'un flux a été prise directement à partir de la accepté de répondre à partir de la discussion: comment générer un flux à partir d'une chaîne de caractères?
Tests
longString
est un 99,1 millions de dollars chaîne de caractères composée de 89 copies de la plaine-version texte de la spécification du langage C#. Les résultats indiqués sont pour les 20 itérations. Où il y a un "démarrage", le temps (comme pour la première itération de la créé implicitement tableau dans la méthode n ° 3), j'ai testé séparément, comme par la rupture de la boucle après la première itération.
Résultats
De mes tests, la mise en cache à la chaîne dans un char tableau à l'aide de la ToCharArray() est la méthode la plus rapide pour parcourir l'ensemble de la chaîne. Le ToCharArray() la méthode est de charge initiale, et l'accès ultérieur à des caractères individuels est légèrement plus rapide que par le haut dans l'index de l'accesseur.
milliseconds
---------------------------------
Method Startup Iteration Total StdDev
------------------------------ ------- --------- ----- ------
1 index accessor 0 602 602 3
2 explicit convert ToCharArray 165 410 582 3
3 foreach (c in string.ToCharArray)168 455 623 3
4 StringReader 0 1150 1150 25
5 StreamWriter => Stream 405 1940 2345 20
6 GetBytes() => StreamReader 385 2065 2450 35
7 GetBytes() => BinaryReader 385 5465 5850 80
8 foreach (c in string) 0 960 960 4
Mise à jour: Par @Eric commentaire, voici les résultats pour 100 itérations sur une plus normal 1,1 M de chaîne de char (une copie de la C# spec). L'indexeur et des tableaux de char sont encore plus rapide, suivie par foreach(char en string), suivis par les flux de méthodes.
milliseconds
---------------------------------
Method Startup Iteration Total StdDev
------------------------------ ------- --------- ----- ------
1 index accessor 0 6.6 6.6 0.11
2 explicit convert ToCharArray 2.4 5.0 7.4 0.30
3 for(c in string.ToCharArray) 2.4 4.7 7.1 0.33
4 StringReader 0 14.0 14.0 1.21
5 StreamWriter => Stream 5.3 21.8 27.1 0.46
6 GetBytes() => StreamReader 4.4 23.6 28.0 0.65
7 GetBytes() => BinaryReader 5.0 61.8 66.8 0.79
8 foreach (c in string) 0 10.3 10.3 0.11
Code Utilisé (testé séparément; représenté pour des raisons de concision)
//1 index accessor
int strLength = longString.Length;
for (int i = 0; i < strLength; i++) { c = longString[i]; }
//2 explicit convert ToCharArray
int strLength = longString.Length;
char[] charArray = longString.ToCharArray();
for (int i = 0; i < strLength; i++) { c = charArray[i]; }
//3 for(c in string.ToCharArray)
foreach (char c in longString.ToCharArray()) { }
//4 use StringReader
int strLength = longString.Length;
StringReader sr = new StringReader(longString);
for (int i = 0; i < strLength; i++) { c = Convert.ToChar(sr.Read()); }
//5 StreamWriter => StreamReader
int strLength = longString.Length;
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(longString);
writer.Flush();
stream.Position = 0;
StreamReader str = new StreamReader(stream);
while (stream.Position < strLength) { c = Convert.ToChar(str.Read()); }
//6 GetBytes() => StreamReader
int strLength = longString.Length;
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(longString));
StreamReader str = new StreamReader(stream);
while (stream.Position < strLength) { c = Convert.ToChar(str.Read()); }
//7 GetBytes() => BinaryReader
int strLength = longString.Length;
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(longString));
BinaryReader br = new BinaryReader(stream, Encoding.Unicode);
while (stream.Position < strLength) { c = br.ReadChar(); }
//8 foreach (c in string)
foreach (char c in longString) { }
Accepté de répondre:
J'ai interprété @CodeInChaos et Ben notes comme suit:
fixed (char* pString = longString) {
char* pChar = pString;
for (int i = 0; i < strLength; i++) {
c = *pChar ;
pChar++;
}
}
Exécution pour 100 itérations au cours de la courte chaîne était de 4,4 ms, avec < 0,1 ms st dev.