Czy ktoś zaimplementował parsera Regex i / lub Xml wokół StringBuilders lub Streams?

Buduję klienta testującego stres, który wbija serwery i analizuje odpowiedzi przy użyciu tylu wątków, ile może zgromadzić klient. Ciągle odkrywam, że ograniczam się do usuwania śmieci (i / lub ich braku), aw większości przypadków sprowadza się to do ciągów znaków, które tworzę tylko po to, aby przekazać je do procedury Regex lub parsowania Xml.

Jeśli zdekompilujesz klasę Regex, zobaczysz towewnętrznie, używa StringBuilders do prawie wszystkiego, ale nie możeszprzechodzić to budowniczy strun; przed rozpoczęciem korzystania z nich pomocna jest metoda prywatna, więc metody rozszerzenia nie rozwiążą jej. Jesteś w podobnej sytuacji, jeśli chcesz uzyskać wykres obiektu z parsera w System.Xml.Linq.

Nie jest to przypadek nadmiernej optymalizacji z wyprzedzeniem. Spojrzałem naRegex zastępuje wewnątrz StringBuilder pytanie i inne. Profilowałem też moją aplikację, aby zobaczyć, skąd pochodzą sufity i używaćRegex.Replace() teraz rzeczywiście wprowadza znaczący narzut w łańcuchu metod, w którym próbuję trafić na serwer z milionami żądań na godzinę i sprawdzić odpowiedzi XML na błędy i wbudowane kody diagnostyczne. Pozbyłem się już prawie wszystkich innych nieskuteczności, które ograniczają przepustowość, a nawet wyciąłem sporo nakładów Regex, rozszerzając StringBuilder, aby zrobił znak zastępczy znajdowania / zastępowania, gdy nie potrzebuję grup przechwytywania lub backreferences, ale wydaje mi się, że ktoś zawinąłby teraz niestandardowe narzędzie String Regu i Xml oparte na Stream'u.

Ok, więc rant, ale czy będę musiał to zrobić sam?

Aktualizacja: Znalazłem obejście, które obniżyło maksymalne zużycie pamięci z wielu gigabajtów do kilkuset megabajtów, więc zamieszczam to poniżej. Nie dodaję go jako odpowiedzi, ponieważ a) Zasadniczo nie lubię tego robić, b) Nadal chcę dowiedzieć się, czy ktoś poświęca czas na dostosowanie StringBuilder do Regexes (lub odwrotnie), zanim to zrobię.

W moim przypadku nie mogłem użyć XmlReader, ponieważ strumień, który przyjmuję, zawiera pewne nieprawidłowe elementy binarne w niektórych elementach. Aby przeanalizować XML, muszę opróżnić te elementy. Wcześniej użyłem pojedynczej statycznej skompilowanej instancji Regex do wykonania zamiany, a to pochłonęło pamięć jak szalona (próbuję przetworzyć ~ 300 10 KB docs / s). Zmiana, która drastycznie zmniejszyła zużycie, była następująca:

Dodałem kod z tegoArtykuł StringBuilder Extensions na CodeProject na poręczneIndexOf metoda.Dodałem (bardzo) surowyWildcardReplace metoda, która pozwalajeden znak wieloznaczny (* lub?) na wywołanieZastąpiłem użycie RegexaWildcardReplace() zadzwoń, aby opróżnić zawartość obraźliwych elementów

Jest to bardzo nieprecyzyjne i testowane tylko w zakresie, w jakim wymaga tego mój własny cel; Zrobiłbym to bardziej eleganckim i potężnym, ale YAGNI i tak dalej, a ja się spieszę. Oto kod:

/// <summary>
/// Performs basic wildcard find and replace on a string builder, observing one of two 
/// wildcard characters: * matches any number of characters, or ? matches a single character.
/// Operates on only one wildcard per invocation; 2 or more wildcards in <paramref name="find"/>
/// will cause an exception.
/// All characters in <paramref name="replaceWith"/> are treated as literal parts of 
/// the replacement text.
/// </summary>
/// <param name="find"></param>
/// <param name="replaceWith"></param>
/// <returns></returns>
public static StringBuilder WildcardReplace(this StringBuilder sb, string find, string replaceWith) {
    if (find.Split(new char[] { '*' }).Length > 2 || find.Split(new char[] { '?' }).Length > 2 || (find.Contains("*") && find.Contains("?"))) {
        throw new ArgumentException("Only one wildcard is supported, but more than one was supplied.", "find");
    } 
    // are we matching one character, or any number?
    bool matchOneCharacter = find.Contains("?");
    string[] parts = matchOneCharacter ? 
        find.Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries) 
        : find.Split(new char[] { '*' }, StringSplitOptions.RemoveEmptyEntries);
    int startItemIdx; 
    int endItemIdx;
    int newStartIdx = 0;
    int length;
    while ((startItemIdx = sb.IndexOf(parts[0], newStartIdx)) > 0 
        && (endItemIdx = sb.IndexOf(parts[1], startItemIdx + parts[0].Length)) > 0) {
        length = (endItemIdx + parts[1].Length) - startItemIdx;
        newStartIdx = startItemIdx + replaceWith.Length;
        // With "?" wildcard, find parameter length should equal the length of its match:
        if (matchOneCharacter && length > find.Length)
            break;
        sb.Remove(startItemIdx, length);
        sb.Insert(startItemIdx, replaceWith);
    }
    return sb;
}

questionAnswers(3)

yourAnswerToTheQuestion