Иногда Я хочу последовательно перебирать символы строки, например, при анализе вложенных токенов - то, что невозможно сделать с помощью регулярных выражений. Мне интересно, какой самый быстрый способ перебирать отдельные символы строки, особенно очень большие строки.
Я сам провел ряд тестов, и мои результаты приведены ниже. Однако есть много читателей с гораздо более глубокими знаниями о компиляторе .NET CLR и C#, поэтому я не знаю, упускаю ли я что-то очевидное или допустил ошибку в своем тестовом коде. Поэтому я прошу вашего коллективного ответа. Если кто-нибудь знает, как на самом деле работает индексатор строк, это будет очень полезно. (Это функция языка C#, скомпилированная во что-то еще за кулисами? Или что-то встроенное в CLR?).
Первый метод с использованием потока был взят непосредственно из принятого ответа ветки: как сгенерировать поток из строки?
Тесты
Код: Выделить всё
longStringРезультаты
Из моих тестов кэширование строки в массиве символов с использованием метода ToCharArray() является самый быстрый для перебора всей строки. Метод ToCharArray() требует предварительных затрат, а последующий доступ к отдельным символам происходит немного быстрее, чем встроенный метод доступа к индексу.
Код: Выделить всё
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
Код: Выделить всё
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
Код: Выделить всё
//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) { }
Я интерпретировал @CodeInChaos и примечания Бена следующим образом:
Код: Выделить всё
fixed (char* pString = longString) {
char* pChar = pString;
for (int i = 0; i < strLength; i++) {
c = *pChar ;
pChar++;
}
}
Подробнее здесь: https://stackoverflow.com/questions/879 ... -string-in