Wie kann ich die split ein string von strings und zählen der Trennzeichen verwenden .NET?

Gibt es viele ähnliche Fragen, aber anscheinend nicht perfekt übereinstimmen, das ist, warum ich Frage.

Ich möchte teilen Sie eine zufällige Zeichenfolge (z.B. 123xx456yy789) von einer Liste von string-Begrenzungszeichen (z.B. xx, yy), und nehmen Sie das Trennzeichen in das Ergebnis (hier: 123, xx, 456, yy, 789).

Gute Leistung ist ein netter bonus. Regex sollte vermieden werden, wenn möglich.

Update: ich habe einige performance-checks und die Ergebnisse verglichen (zu faul, um formell überprüfen, Sie wenn). Die getesteten Lösungen sind (in zufälliger Reihenfolge):

  1. Gabe
  2. Guffa
  3. Mafu
  4. Regex

Andere Lösungen wurden nicht geprüft, weil entweder waren Sie ähnlich zu einer anderen Lösung oder Sie kamen zu spät.

Dies ist der test-code:

class Program
{
    private static readonly List<Func<string, List<string>, List<string>>> Functions;
    private static readonly List<string> Sources;
    private static readonly List<List<string>> Delimiters;

    static Program ()
    {
        Functions = new List<Func<string, List<string>, List<string>>> ();
        Functions.Add ((s, l) => s.SplitIncludeDelimiters_Gabe (l).ToList ());
        Functions.Add ((s, l) => s.SplitIncludeDelimiters_Guffa (l).ToList ());
        Functions.Add ((s, l) => s.SplitIncludeDelimiters_Naive (l).ToList ());
        Functions.Add ((s, l) => s.SplitIncludeDelimiters_Regex (l).ToList ());

        Sources = new List<string> ();
        Sources.Add ("");
        Sources.Add (Guid.NewGuid ().ToString ());

        string str = "";
        for (int outer = 0; outer < 10; outer++) {
            for (int i = 0; i < 10; i++) {
                str += i + "**" + DateTime.UtcNow.Ticks;
            }
            str += "-";
        }
        Sources.Add (str);

        Delimiters = new List<List<string>> ();
        Delimiters.Add (new List<string> () { });
        Delimiters.Add (new List<string> () { "-" });
        Delimiters.Add (new List<string> () { "**" });
        Delimiters.Add (new List<string> () { "-", "**" });
    }

    private class Result
    {
        public readonly int FuncID;
        public readonly int SrcID;
        public readonly int DelimID;
        public readonly long Milliseconds;
        public readonly List<string> Output;

        public Result (int funcID, int srcID, int delimID, long milliseconds, List<string> output)
        {
            FuncID = funcID;
            SrcID = srcID;
            DelimID = delimID;
            Milliseconds = milliseconds;
            Output = output;
        }

        public void Print ()
        {
            Console.WriteLine ("S " + SrcID + "\tD " + DelimID + "\tF " + FuncID + "\t" + Milliseconds + "ms");
            Console.WriteLine (Output.Count + "\t" + string.Join (" ", Output.Take (10).Select (x => x.Length < 15 ? x : x.Substring (0, 15) + "...").ToArray ()));
        }
    }

    static void Main (string[] args)
    {
        var results = new List<Result> ();

        for (int srcID = 0; srcID < 3; srcID++) {
            for (int delimID = 0; delimID < 4; delimID++) {
                for (int funcId = 3; funcId >= 0; funcId--) { //i tried various orders in my tests
                    Stopwatch sw = new Stopwatch ();
                    sw.Start ();

                    var func = Functions[funcId];
                    var src = Sources[srcID];
                    var del = Delimiters[delimID];

                    for (int i = 0; i < 10000; i++) {
                        func (src, del);
                    }
                    var list = func (src, del);
                    sw.Stop ();

                    var res = new Result (funcId, srcID, delimID, sw.ElapsedMilliseconds, list);
                    results.Add (res);
                    res.Print ();
                }
            }
        }
    }
}

Wie Sie sehen können, es war wirklich nur ein quick-and-dirty-test, aber ich lief der test mehrmals und mit verschiedenen um-und das Ergebnis war immer sehr konsequent. Die gemessenen Zeitspannen liegen im Bereich von Millisekunden bis zu Sekunden, für größere Datenmengen. Ich ignorierte die Werte im niedrigen Millisekundenbereich in meiner folgenden Bewertung, denn Sie Schienen in der Praxis vernachlässigbar. Hier ist die Ausgabe auf meine box:

S 0 D 0 F 3 11ms 
1 
S 0 D 0 F 2 7ms 
1 
S 0 D 0 F 1 6ms 
1 
S 0 D 0 F 0 4ms 
0 
S 0 D 1 F 3 28ms 
1 
S 0 D 1 F 2 8ms 
1 
S 0 D 1 F 1 7ms 
1 
S 0 D 1 F 0 3ms 
0 
S 0 D 2 F 3 30ms 
1 
S 0 D 2 F 2 8ms 
1 
S 0 D 2 F 1 6ms 
1 
S 0 D 2 F 0 3ms 
0 
S 0 D 3 F 3 30ms 
1 
S 0 D 3 F 2 10ms 
1 
S 0 D 3 F 1 8ms 
1 
S 0 D 3 F 0 3ms 
0 
S 1 D 0 F 3 9ms 
1 9e5282ec-e2a2-4... 
S 1 D 0 F 2 6ms 
1 9e5282ec-e2a2-4... 
S 1 D 0 F 1 5ms 
1 9e5282ec-e2a2-4... 
S 1 D 0 F 0 5ms 
1 9e5282ec-e2a2-4... 
S 1 D 1 F 3 63ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 1 F 2 37ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 1 F 1 29ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 1 F 0 22ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 2 F 3 30ms 
1 9e5282ec-e2a2-4... 
S 1 D 2 F 2 10ms 
1 9e5282ec-e2a2-4... 
S 1 D 2 F 1-10ms 
1 9e5282ec-e2a2-4... 
S 1 D 2 F 0 12ms 
1 9e5282ec-e2a2-4... 
S 1 D 3 F 3 73ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 3 F 2 40ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 3 F 1 33ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 1 D 3 F 0 30ms 
9 9e5282ec - e2a2 - 4265 - 8276 - 6dbb50fdae37 
S 2 D 0 F 3 10ms 
1 0**634226552821... 
S 2 D 0 F 2 109ms 
1 0**634226552821... 
S 2 D 0 F 1 5ms 
1 0**634226552821... 
S 2 D 0 F 0 127ms 
1 0**634226552821... 
S 2 D 1 F 3 184ms 
21 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226 
552821... - 0**634226552821... - 
S 2 D 1 F 2 364ms 
21 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226 
552821... - 0**634226552821... - 
S 2 D 1 F 1 134ms 
21 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226 
552821... - 0**634226552821... - 
S 2 D 1 F 0 517ms 
20 0**634226552821... - 0**634226552821... - 0**634226552821... - 0**634226 
552821... - 0**634226552821... - 
S 2 D 2 F 3 688ms 
201 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 2 F 2 2404ms 
201 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 2 F 1 874ms 
201 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 2 F 0 717ms 
201 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 3 F 3 1205ms 
221 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 3 F 2 3471ms 
221 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 3 F 1 1008ms 
221 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... ** 
S 2 D 3 F 0 1095ms 
220 0 ** 634226552821217... ** 634226552821217... ** 634226552821217... ** 6 
34226552821217... **

Ich die Ergebnisse verglichen und das ist, was ich gefunden habe:

  • Alle 4 Funktionen sind schnell genug für die gemeinsame Nutzung.
  • Die naive version (aka das, was ich schrieb zunächst) das Schlimmste in Bezug auf die Rechenzeit.
  • Regex ist ein bisschen langsam, auf kleinen Datenmengen (wahrscheinlich aufgrund der Initialisierungs-overhead).
  • Regex funktioniert gut auf großen Daten-und schlägt in eine ähnliche Geschwindigkeit wie die nicht-regex-Lösungen.
  • Die leistungsmäßig am besten scheint zu sein, Guffa-version insgesamt, die zu erwarten ist, aus dem code.
  • Gabe, die version manchmal lässt ein Element, aber das habe ich nicht untersuchen, diese (Fehler?).

Um das Thema abzuschließen, empfehle ich Regex, die ist halbwegs schnell. Wenn Leistung wichtig ist, würde ich es vorziehen, Guffa Umsetzung.

InformationsquelleAutor mafu | 2010-03-20

Schreibe einen Kommentar