Scan ning birinchi versiyasi, kompilyatsiya vaqtida holat mashinasi tuzilishiga ega C++ uchun matnni tahlil qilish kutubxonasi.

Skanerlash kutubxonasining birinchi versiyasi (0.1.0) nashr etildi. U matnni kompilyatsiya vaqti naqshiga asoslangan qiymatlarga ajratadi. Naqsh yoki format C++ shablon argumenti sifatida yoziladi va C++ shablonlari yordamida kompilyatsiya vaqti kodiga holatma-holat ochiladigan teglangan deterministik chekli avtomatga (TDFA) kompilyatsiya qilinadi. Bajarish natijasi so'ralgan turdagi qiymatdir. Loyiha kodi C++23 da yozilgan va GPLv3 litsenziyasi ostida tarqatiladi. import scan; // Butun satr mos keladimi? Har bir kirish nuqtasi ham diapazon adapteridir. scan::match<«[az]+@[az.]+»>(manzil); manzil | scan::match<«[az]+@[az.]+»>; // Guruhlar bilan. const auto found = scan::match<«([0-9]+)-([az]+)»>(«42-abc»); found.get<1>().to_view(); // "42" // Naqsh egallagan satrning boshi va istalgan joyda birinchi moslik. scan::starts_with<«[a-z]+»>(«abc123»).whole().to_view(); // "abc" scan::search<«[0-9]+»>(«id=4210x»).to_view(); // "4210" // Barcha mosliklar va ularning orasidagi qismlar dangasa ko'rinishlardir. for (const auto& one : text | scan::search_all<«[a-z]+»>) { … } const auto fields = "a,bb,,ccc" | scan::split<«,»> | std::ranges::to (); // Qiymatlar, matn emas. struct row { int id; std::string_view name; }; const row one = scan::scan<«{},{[a-z]+}»>(satr); // Ro'yxat, turlar yig'indisi, ichki shakl. struct all { std::vector qiymatlar; std::variant tail; }; const all got = scan::scan<«{{}{*,?}} {{[0-9]+}|{[a-z]+}}»>(«1,2,3 abc»); // Kiruvchi ma'lumotlarning boshlanishi va undan qolgan ma'lumotlar. const auto [value, rest] = scan::scan_prefix<«{},{}»>(satr).take (); // Bir vaqtning o'zida bitta yozuv, istalgan narsadan. for (const row& one : scan::each<«{},{[az]+}\\n»>(text).of ()) { … }

Faqat bir marta o'qilishi mumkin bo'lgan diapazon buferlashsiz o'qiladi, belgilar kelishi bilan maydonlar to'planadi. Tutilishi kerak bo'lgan belgilar soni kompilyatsiya vaqtidagi naqsh bilan belgilanadi; bu raqam mavjud bo'lmagan hollarda, kompilyatsiya vaqtida o'qish rad etiladi. 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 (manba)). ning ()) { … } Ishlash.

O'lchovlar libc++, -O3 -march=native,LTO bilan 22.1.8 ga ega Ryzen 9 9950X protsessorida amalga oshirildi. Har bir o'tishda 32 ta yozuv, yettita o'tishning medianasi. "([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 bir xil beshta maydon, har biri ikki yuz harfdan iborat scan::scan .sentinel() 57.8 ns re2c 637 ns CTRE 692 ns RE2 11751 ns "first.last@subdomain.example.com" ni tanib olish, hech narsa olinmadi scan::match .sentinel().scalar() 436 ns scan::match .scalar() 545 ns re2c 1186 ns RE2 2616 ns CTRE 14339 ns Tahlil qilinayotgan guruhlar qulashi

Turga keyingi belgi qaysi guruhga tegishli ekanligi aytiladi va baholash joyida amalga oshiriladi: hech qanday sikl iteratsiyalari saqlanmaydi, hech qanday pastki satrlar yaratilmaydi. 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 jami = 0; unsigned place = 0, marks = 0; }; static constexpr state_type begin_groups() { return {}; } static constexpr void opened_group(holat_turi& one, scan::group_at<0>) { one.place = 0; one.marks = 0; } static constexpr void closed_group(holat_turi& 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(holat_turi& one, scan::group_at<1>, char) { ++one.place; } static constexpr void push_group(holat_turi& one, scan::group_at<2>, char harfi) { one.marks += harf == 'Y' ? 2u: 1u; } static constexpr finish_groups(holat_turi& one) { return {one.total}; } }; const o'qish got = scan::scan<“value={}{[az]*}”>(“value=(__X_XX)abcdefgh”).of (); // oldim.raqam.qiymati == 12, oldim.quyruq == "abcdefgh"

uyumni skanerlash::skanerlash .scalar() qo'lda yozilgan 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
Kontekstlar va ajratuvchilar

Har qanday chaqiruvchi obyekti — ajratuvchi, hovuz, arena va boshqa narsalar — qiymatni yaratadigan chaqiruvga o'tkazilishi mumkin. Kontekst turi yo'qolmaydi: skaner holati va uning har bir ilgagi unga shablon sifatida kiritilishi mumkin, shuning uchun skanerda chaqiruvchi turi ko'rsatilmaydi. struct arena { std::pmr::memory_resource* where = nullptr; std::pmr::memory_resource* resource() const { return where; } }; struct numbers { std::pmr::vector qiymatlar; }; struktura ikkalasi ham { chapdagi raqamlar; o'ngdagi raqamlar; }; shablon <> struktura scan::scanner { static constexpr std::string_view naqsh() { return "([0-9]+)(?:,([0-9]+))*"; } shablon struktura holati { std::pmr::vector qiymatlar; int ishlayapti = 0; }; statik holat begin_groups() { return {}; } shablon statik holatni talab qiladi (const Told& one) { one.resource(); } start_groups(const Aytilgan va aytilgan) { return {std::pmr::vector (told.resource()), 0}; } shablon static void push_group(holat) va bitta, scan::group_at , char raqami) { one.running = one.running * 10 + (raqam - '0'); } shablon static void closed_group(holat) va bitta, scan::group_at ) { one.values.push_back(one.running); one.running = 0; } shablon statik raqamlar finish_groups(holat) one) { return {std::move(one.values)}; } }; std::pmr::monotonic_buffer_resource baytlari; const arena meniki{&bytes}; scan::scan<“{} {}”>(matn).of (mine); // ikkala joy uchun bitta scan::scan<«{} {}»>(text).of (mine, scan::default_context); // har bir joyga bittadan scan::scan<“{} {}”>(text).of ({mine, scan::default_context}); // qavs ichida bir xil const both got = scan::scan<«{} {}»>(text).with(mine); // Kontekst uning turi bo'lishi shart emas: ajratuvchi quyidagi darajaga yetadi // read.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 chaqiruvchining obyektini nusxasini emas, balki o'zi qabul qiladi, shuning uchun holat uning manzilini saqlashi mumkin: kontekst chaqiruv davomida saqlanib qoladi va barcha o'qish shu chaqiruv ichida sodir bo'ladi. Boshqa xususiyatlar

  • Ikki qatlam: shablon qatlami (match, starts_with, search, search_all, split) va format qatlami, bu yerda "{}" maydon bo'lib, o'rin qiymati esa turning o'zidagi maydonlar tomonidan belgilanadi.
  • Perl, RE2 va CTRE tillaridagi kabi, ikki xil qoida chapdan birinchi bo'lib qo'llaniladi.
  • Yuqoridagilarning barchasi doimiy ifodalarda ham ishlaydi.
  • Hech qanday vaqtinchalik qidiruvlar, orqaga havolalar yoki Unicode xususiyatlari yo'q; shablonlar baytlarda ishlaydi.
  • Faqat ish vaqtida ma'lum bo'lgan naqshlar qo'llab-quvvatlanmaydi.

O'rnatish

Clang va GCC bilan kompilyatsiya qilinadi. C++ modullari ixtiyoriy: demodulizer yordamchi dasturi tomonidan bir xil modullardan yaratilgan sarlavha fayllari (include/) mavjud — har bir push asosiy qayta qurish, havolalar va ularni topshirishga olib keladi. C++26 bog'lash paketlari yoqilganda yagona bog'liqlik, Boost.PFR, kerak emas. 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)

Manba: opennet.ru

DDoS himoyasi, VPS VDS serverlari bo'lgan saytlar uchun ishonchli hosting sotib oling 🔥 DDoS himoyasi, VPS VDS serverlari bilan ishonchli veb-sayt xostingini sotib oling | ProHoster