0Pricing
C++ Academy · Lekcja

Uwagi dotyczące wydajności

Rozważnie kompiluj wzorce

Uwagi dotyczące wydajności to bezpłatna lekcja C++ Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C++ Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C++ Academy zawiera 4 lekcji w sumie.

Kompilacja jest kosztowna

Utworzenie obiektu std::regex na podstawie łańcucha kompiluje wzorzec, co jest kosztowne. Największą korzyść daje skompilowanie go raz i ponowne używanie.

  • Należy unikać konstruowania obiektu regex wewnątrz pętli.
  • Należy kompilować wzorzec podczas uruchamiania programu lub przy pierwszym użyciu.
#include <iostream>
#include <regex>

int main() {
    std::regex p("\\d+");
    std::string inputs[] = {"12", "ab", "99"};
    for (const auto& s : inputs) {
        std::cout << s << ": " << std::regex_match(s, p) << '\n';
    }
    return 0;
}

Ponowne użycie skompilowanego wzorca

Należy skonstruować wzorzec raz, poza pętlą, i używać go ponownie dla każdego wejścia. Jego odbudowywanie przy każdej iteracji marnuje czas.

#include <iostream>
#include <regex>
#include <vector>

int main() {
    static const std::regex p("[a-z]+");
    std::vector<std::string> words = {"hello", "WORLD", "cpp"};
    int matches = 0;
    for (const auto& w : words) {
        if (std::regex_match(w, p)) ++matches;
    }
    std::cout << "Matched: " << matches << '\n';
    return 0;
}

static const dla stałych

Jeśli wzorzec nigdy się nie zmienia, należy zadeklarować go jako static const wewnątrz funkcji, aby został skompilowany dokładnie raz dla wszystkich wywołań.

#include <iostream>
#include <regex>

bool isEmail(const std::string& s) {
    static const std::regex p("\\w+@\\w+\\.\\w+");
    return std::regex_match(s, p);
}

int main() {
    std::cout << std::boolalpha;
    std::cout << isEmail("a@b.com") << '\n';
    std::cout << isEmail("nope") << '\n';
    return 0;
}

Wybór właściwej gramatyki

Wariant wyrażeń regularnych (gramatyka) wpływa na szybkość i dostępne funkcje. std::regex::ECMAScript jest domyślny i najbardziej rozbudowany, natomiast std::regex::basic lub extended są prostsze i czasami szybsze.

#include <iostream>
#include <regex>

int main() {
    std::regex p("a+", std::regex::extended);
    std::cout << std::boolalpha << std::regex_match("aaa", p) << '\n';
    return 0;
}

Flaga optimize

Dodanie std::regex::optimize informuje silnik, aby poświęcił więcej czasu na budowanie wzorca w zamian za szybsze dopasowywanie. Opłaca się to, gdy dopasowanie jest wykonywane wiele razy.

#include <iostream>
#include <regex>

int main() {
    std::regex p("\\d{3}-\\d{4}", std::regex::optimize);
    std::cout << std::boolalpha << std::regex_match("123-4567", p) << '\n';
    return 0;
}

Unikanie katastrofalnego backtrackingu

Zagnieżdżone kwantyfikatory, takie jak (a+)+, mogą dla określonych danych wejściowych doprowadzić do wykładniczego wzrostu czasu działania. Należy wybierać prostsze i jednoznaczne wzorce.

#include <iostream>
#include <regex>

int main() {
    std::regex good("a+b");
    std::cout << std::boolalpha << std::regex_match("aaaab", good) << '\n';
    return 0;
}

Stosowanie kotwic, gdy to możliwe

Zakotwiczenie wzorca za pomocą ^ i $ pozwala silnikowi szybko zakończyć nieudaną próbę, zamiast sprawdzać każdą pozycję początkową.

#include <iostream>
#include <regex>

int main() {
    std::regex p("^[a-z]{3}$");
    std::cout << std::boolalpha;
    std::cout << std::regex_search("abc", p) << '\n';
    std::cout << std::regex_search("abcd", p) << '\n';
    return 0;
}

W miarę możliwości wybieraj proste narzędzia

Jeśli potrzebne jest tylko sprawdzenie stałego podłańcucha, std::string::find jest znacznie szybsze niż wyrażenie regularne. Wyrażeń regularnych należy używać wtedy, gdy rzeczywiście potrzebne jest dopasowywanie wzorca.

#include <iostream>
#include <string>

int main() {
    std::string s = "hello world";
    bool has = s.find("world") != std::string::npos;
    std::cout << std::boolalpha << has << '\n';
    return 0;
}

Ponowne używanie obiektu dopasowania

Przy wielokrotnym wyszukiwaniu należy ponownie używać jednego obiektu std::smatch zamiast za każdym razem tworzyć nowy, aby zmniejszyć narzut.

#include <iostream>
#include <regex>
#include <vector>

int main() {
    static const std::regex p("(\\d+)");
    std::smatch m;
    std::vector<std::string> data = {"x1", "y22", "z333"};
    for (const auto& s : data) {
        if (std::regex_search(s, m, p)) std::cout << m[1] << ' ';
    }
    std::cout << '\n';
    return 0;
}

Zawężanie wzorca

Określone klasy znaków dopasowują się szybciej i bezpieczniej niż kropka oznaczająca dowolny znak. Należy używać [0-9] zamiast ., gdy chodzi o cyfry.

#include <iostream>
#include <regex>

int main() {
    std::regex specific("[0-9]{2}");
    std::cout << std::boolalpha;
    std::cout << std::regex_match("42", specific) << '\n';
    std::cout << std::regex_match("ab", specific) << '\n';
    return 0;
}

Zmierz przed optymalizacją

Połącz zdobytą wiedzę o <chrono>: mierz czas użycia wyrażeń regularnych, aby potwierdzić, że dana zmiana rzeczywiście pomaga, zanim zostanie na stałe wprowadzona.

#include <iostream>
#include <regex>
#include <chrono>

int main() {
    using namespace std::chrono;
    static const std::regex p("\\d+");
    auto s = steady_clock::now();
    int hits = 0;
    for (int i = 0; i < 1000; ++i) {
        if (std::regex_search(std::string("x") + std::to_string(i), p)) ++hits;
    }
    auto e = steady_clock::now();
    std::cout << "hits=" << hits << ", timed: " << ((e - s).count() >= 0) << '\n';
    return 0;
}

Szybkie sprawdzenie

Sprawdź swoją wiedzę na temat wydajności wyrażeń regularnych.

Podsumowanie

Nauczyłeś się, jak wydajnie używać wyrażeń regularnych:

  • kompiluj wzorce raz, najlepiej jako static const, i używaj ich ponownie
  • wybieraj odpowiednią gramatykę i rozważ użycie optimize
  • unikaj katastrofalnego wycofywania i stosuj kotwice, gdy to możliwe
  • używaj prostszych narzędzi, takich jak find, dla stałych podciągów oraz mierz wprowadzane zmiany

To kończy kurs wyrażeń regularnych.

Często zadawane pytania

Czy lekcja „Uwagi dotyczące wydajności” jest bezpłatna?

Tak — pełny tekst „Uwagi dotyczące wydajności” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C++ Academy, przejdź na CoddyKit PRO. Kurs C++ Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Uwagi dotyczące wydajności”?

Rozważnie kompiluj wzorce Ćwiczysz C++ Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C++ Academy?

Nie wymagamy żadnego doświadczenia. C++ Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Uwagi dotyczące wydajności”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C++ Academy?

Tak. Każda lekcja C++ Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Podstawy regex
  2. Grupy przechwytujące
  3. Wyszukiwanie i zastępowanie
  4. Uwagi dotyczące wydajności
← Powrót do C++ Academy