Tak dla zabawy, pisałem trochę odniesienia do perf-przetestować wszystkie te odpowiedzi (w tym inne moją odpowiedź powyżej). Oto wyniki w mojej stacji roboczej (32-bitowy Core 2 Duo @ 2.66GHz) dla 5M powtórzeń przy użyciu kompilacji Release:
- LINQ: 10.545 sekundy
- mój Podział + StringBuilder sposób: 3,633 sekund
- podziału wipeck za i dołącz do drogi! : 3,32 sekund
- (Nieskompilowany) regex: 3.845 sek
- (zestawiane) regex: 12.431 s
Wyniki: wipeck jest dzielona i-Dołącz roztwór wygrywa, ale (PO wybrane) roztworu regex był tylko 15% wolniej, co mnie zaskoczyło. Spodziewałem się 100% lub więcej gorzej. Kudos dla programistów .NET Regex dla szybkości.
Moje własne rozwiązanie (używając Split i StringBuilder) było, jak sądziłem, zoptymalizowane pod kątem szybkości, ale wymaga znacznie więcej kodu i nie robi tego szybko. Doh!
Najbardziej zaskakujące, próbowałem skompilowanego rozwiązania regex i było prawie 3x wolniejsze niż nieskompilowane wyrażenie regularne (i nie uwzględniłem czasu kompilacji w wynikach - włącznie z kompilacją byłoby jeszcze gorzej). Tyle dla skompilowanej przewagi regex perf.
LINQ było, jak się spodziewałem, bardzo powolne - nadmiar wszystkich tych dodatkowych obiektów i wywołań metodowych naprawdę się sumuje.
Oto kod testu:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
class Timer : IDisposable
{
private DateTime _start;
private string _name;
public Timer(string name)
{
_name = name;
_start = DateTime.Now;
}
public void Dispose()
{
TimeSpan taken = DateTime.Now - _start;
Console.WriteLine(string.Format ("{0} : {1} seconds", _name, taken.TotalMilliseconds/1000.0));
}
}
class Program
{
static void Main(string[] args)
{
int reps = 5000000;
string oldString = "200 abc def abc [a18943]";
using (new Timer("LINQ"))
{
for (int n = 0; n < reps; n++)
{
string[] a = oldString.Split(' ');
var result = a.Skip(a.Length - 1)
.Select(w => w.Replace("[", "").Replace("]", ""))
.Concat(a.Take(a.Length - 1).Skip(1)).ToArray();
var newString = string.Join(" ", result);
}
}
using (new Timer("my Split + StringBuilder way"))
{
for (int n = 0; n < reps; n++)
{
string[] words = oldString.Split(' ');
StringBuilder sb = new StringBuilder(words[words.Length - 1].Trim('[', ']'));
for (int i = 1; i < words.Length - 1; i++)
{
sb.Append(' ');
sb.Append(words[i]);
}
string newString = sb.ToString();
}
}
using (new Timer("wipeck's Split-and-Join way!"))
{
for (int n = 0; n < reps; n++)
{
string valueString = "200 abc def abc [a18943]";
string[] values = valueString.Split(' ');
string lastWord = values[values.Length - 1];
lastWord = lastWord.Trim('[', ']');
values[0] = lastWord;
string movedValueString = string.Join(" ", values, 0, values.Length - 1);
}
}
using (new Timer("(uncompiled) regex"))
{
for (int n = 0; n < reps; n++)
{
string newString = Regex.Replace(@"^(\w+)(.+) \[(\w+)\]$", oldString, "$3$2");
}
}
Regex regex = new Regex(@"^(\w+)(.+) \[(\w+)\]$", RegexOptions.Compiled);
string newStringPreload = regex.Replace(oldString, "$3$2");
using (new Timer("(compiled) regex"))
{
for (int n = 0; n < reps; n++)
{
string newString = regex.Replace(oldString, "$3$2");
}
}
}
}
+1, bardzo zwięzły. –
To działało Po prostu chcę zrozumieć, jak to działa. Czyste. – NETQuestion
Bardzo czyste. Lubię to. Zastanawiam się tylko, czy RegEx jest tu przesadny? –