Scan-ın ilk buraxılışı, kompilyasiya zamanı vəziyyət maşın quruluşuna malik C++ üçün mətn təhlil kitabxanasıdır.

Skan kitabxanasının ilk buraxılışı (0.1.0) dərc edilib. Mətni kompilyasiya vaxtı şablonuna əsasən dəyərlərə ayırır. Şablon və ya format C++ şablon arqumenti kimi yazılır və C++ şablonlarından istifadə edərək kompilyasiya vaxtı koduna çevrilən etiketli deterministik sonlu avtomata (TDFA) kompilyasiya edilir. İcra nəticəsi tələb olunan tipin dəyəridir. Layihə kodu C++23 dilində yazılıb və GPLv3 lisenziyası altında paylanır. import scan; // Bütün sətir uyğun gəlirmi? Hər giriş nöqtəsi də diapazon adapteridir. scan::match<«[az]+@[az.]+»>(ünvan); ünvan | scan::match<«[az]+@[az.]+»>; // Qruplarla. const auto found = scan::match<«([0-9]+)-([az]+)»>(«42-abc»); found.get<1>().to_view(); // "42" // Nümunə ilə tutulmuş sətrin başlanğıcı və istənilən yerdəki ilk uyğunluq. scan::starts_with<«[a-z]+»>(«abc123»).whole().to_view(); // "abc" scan::search<«[0-9]+»>(«id=4210x»).to_view(); // "4210" // Bütün uyğunluqlar və aralarındakı hissələr tənbəl görünüşlərdir. for (const auto& one : text | scan::search_all<«[a-z]+»>) { … } const auto fields = "a,bb,,ccc" | scan::split<«,»> | std::ranges::to (); // Dəyərlər, mətn deyil. struct row { int id; std::string_view name; }; const row one = scan::scan<«{},{[a-z]+}»>(sətir); // Siyahı, növlərin cəmi, iç-içə forma. struct all { std::vector dəyərlər; std::variant tail; }; const all got = scan::scan<«{{}{*,?}} {{[0-9]+}|{[a-z]+}}»>(«1,2,3 abc»); // Girişin başlanğıcı və ondan qalanlar. const auto [dəyər, istirahət] = scan::scan_prefix<«{},{}»>(sətir).take (); // İstənilən yazıdan bir qeyd. for (const row& one : scan::each<«{},{[az]+}\\n»>(text).of ()) { … }

Yalnız bir dəfə oxuna bilən diapazon, simvollar gəldikcə toplanan sahələrlə buferləşdirmədən oxunur. Saxlanılacaq simvolların sayı kompilyasiya zamanı şablonla müəyyən edilir; bu rəqəm mövcud olmadığı təqdirdə, kompilyasiya zamanı oxumaq rədd edilir. std::istringstream source(«set speed 42\\nset gain 7\\n»); source > std::noskipws; struct command { scan::held<16> name; int value; }; for (const command& one : scan::each<«set {[a-z]+} {[0-9]+}\\n»>(std::views::istream (mənbə)). of ()) { … } Performans.

Ölçmələr libc++, -O3 -march=native,LTO ilə 22.1.8 clang 22.1.8 Ryzen 9 9950X prosessorunda aparılmışdır. Hər keçiddə 32 yazı, yeddi keçidin medianı. "([az]+),([az]+),([az]+),([az]+)" "alpha,bravo,charlie,delta,echo" scan::scan .sentinel() 477 ns re2c 554 ns scan::scan 659 ns CTRE 717 ns RE2 15986 ns eyni beş sahə, hər biri iki yüz hərf scan::scan .sentinel() 57.8 ns re2c 637 ns CTRE 692 ns RE2 11751 ns "first.last@subdomain.example.com" tanınması, heç nə alınmadı scan::match .sentinel().scalar() 436 ns scan::match .scalar() 545 ns re2c 1186 ns RE2 2616 ns CTRE 14339 ns Təhlil edildikcə qrupların dağılması

Növbəti simvolun hansı qrupa aid olduğu tipə deyilir və qiymətləndirmə yerində aparılır: heç bir döngə iterasiyası yadda saxlanılmır, heç bir altsətir yaradılmır. struct tally { unsigned long value = 0; }; struct reading { tally number; std::string_view tail; }; template <> struct scan::scanner { static constexpr std::string_view pattern() { return R"(\\(((_+)(X|Y)*)*\\))"; } struct state_type { unsigned long cəm = 0; unsigned place = 0, marks = 0; }; static constexpr state_type begin_groups() { return {}; } static constexpr void opened_group(state_type& one, scan::group_at<0>) { one.place = 0; one.marks = 0; } static constexpr void closed_group(state_type& one, scan::group_at<0>) { unsigned long weight = 1; for (unsigned step = 1; step < one.place; ++step) weight *= 10; one.total += weight * one.marks; } static constexpr void push_group(state_type& one, scan::group_at<1>, char) { ++one.place; } } static constexpr void push_group(state_type& one, scan::group_at<2>, char letter) { one.marks += letter == 'Y' ? 2u: 1u; } static constexpr tally finish_groups(state_type one) { return {one.total}; } }; const oxunuş got = scan::scan<“value={}{[az]*}”>(“value=(__X_XX)abcdefgh”).of (); // al.number.value == 12, al.quyruq == "abcdefgh"

yığın skanlama::skanlama .scalar() əl ilə yazılmış scan::scan 10 141 ns 41.4 ns 42.5 ns 170 ns 100 439 ns 341 ns 392 ns 1176 ns 1000 3314 ns 3170 ns 3797 ns 11887 ns
Kontekstlər və ayırıcılar

İstənilən çağırıcı obyekti — ayırıcı, hovuz, arena və ya hər hansı bir şey — dəyəri yaradan çağırışa ötürülə bilər. Kontekst növü itirilmir: skaner vəziyyəti və onun hər bir qarmaqları şablonlaşdırıla bilər, beləliklə skanerdə heç bir çağırıcı növü qeyd olunmur. struct arena { std::pmr::memory_resource* where = nullptr; std::pmr::memory_resource* resource() const { return where; } }; struct numbers { std::pmr::vector dəyərlər; }; struktur hər ikisi { soldakı rəqəmlər; sağdakı rəqəmlər; }; şablon <> struktur scan::scanner { static constexpr std::string_view pattern() { qaytarır "([0-9]+)(?:,([0-9]+))*"; } şablon struktur vəziyyəti { std::pmr::vector dəyərlər; int işləyir = 0; }; statik vəziyyət begin_groups() { return {}; } şablonu tələb edir requires(const Told& one) { one.resource(); } statik vəziyyət begin_groups(const Dedi və dedi) { return {std::pmr::vector} (told.resource()), 0}; } şablonu static void push_group(vəziyyət və bir, scan::group_at , simvol rəqəmi) { one.running = one.running * 10 + (rəqəm - '0'); } şablon static void closed_group(state və bir, scan::group_at ) { one.values.push_back(one.running); one.running = 0; } şablon statik ədədlər finish_groups(state) one) { return {std::move(one.values)}; } }; std::pmr::monotonic_buffer_resource baytları; const arena mine{&bytes}; scan::scan<“{} {}”>(mətn).of (mine); // hər iki yer üçün bir scan::scan<«{} {}»>(text).of (mine, scan::default_context); // hər yerə bir scan::scan<“{} {}”>(text).of ({mine, scan::default_context}); // mötərizədə eyni const both got = scan::scan<«{} {}»>(text).with(mine); // Kontekstin onun növü olması vacib deyil: ayırıcı aşağıdakılara qədər gedir // oxumaq üçün bir fayl qurur. struct two { std::pmr::string name; std::pmr::string tail; }; const two kept = scan::scan<«{[az]+} {[az]+}»>(text).of<( std::pmr::polymorphic_allocator<>(&bytes));

Hook, zəng edənin obyektinin surətini deyil, özünü qəbul edir, buna görə də state onun ünvanını saxlaya bilər: kontekst zəng müddətində yaşayır və bütün oxuma həmin zəng daxilində baş verir. Digər Xüsusiyyətlər

  • İki təbəqə: şablon təbəqəsi (match, starts_with, search, search_all, split) və format təbəqəsi, burada "{}" bir sahədir və yer dəyəri növün öz sahələri ilə müəyyən edilir.
  • Perl, RE2 və CTRE-də olduğu kimi, ikimənalılıq qaydası ən soldan birincidir.
  • Yuxarıda göstərilənlərin hamısı sabit ifadələrdə də işləyir.
  • Baxışlar, geri istinadlar və ya Unicode xüsusiyyətləri yoxdur; şablonlar baytlarla işləyir.
  • Yalnız icra zamanı məlum olan nümunələr dəstəklənmir.

Məclis

Clang və GCC ilə kompilyasiya edir. C++ modulları isteğe bağlıdır: demodulizer yardımçı proqramı tərəfindən eyni modullardan yaradılan başlıq faylları (include/) mövcuddur — hər bir push əsas yenidənqurmalara, bağlantılara və onları commit etməyə aparır. Yeganə asılılıq olan Boost.PFR, C++26 bağlama paketləri aktiv olduqda lazım deyil. FetchContent_Declare(scan GIT_REPOSITORY https://github.com/j4niwzis/scan.git GIT_TAG v0.1.0) FetchContent_MakeAvailable(scan) target_link_libraries(mine PRIVATE scan::scan)

Mənbə: opennet.ru

DDoS mühafizəsi, VPS VDS serverləri olan saytlar üçün etibarlı hostinq alın 🔥 DDoS qorunması, VPS VDS serverləri ilə etibarlı veb sayt hostinqi alın | ProHoster