6-bo‘lim

Satrlar

std::string, std::string_view va nima uchun ikkalasi ham kerak.

🕑 11 daqiqa o‘qish 📄 404 so‘z 👁 2 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. std::string asoslari
  2. Satrlarni birlashtirish va o'zgartirish
  3. Qidirish
  4. std::string_view - nusxasiz ko'rinish
  5. string_view ning xavfi
  6. Satrni bo'laklarga ajratish
  7. Sonlarni satrga va aksincha
  8. Satrlarni solishtirish
  9. Kichik satr optimallashtirishi
  10. Xulosa

C da satr - nol bilan tugaydigan char massivi. Uzunlikni bilish uchun butun massivni aylanib chiqish kerak, hajmni o'zgartirish esa qo'lda qilinadi.

C++ da std::string bu ishlarni o'z zimmasiga oladi.

std::string asoslari #

C++
#include <print>
#include <string>
#include <string_view>
#include <vector>
#include <algorithm>
#include <sstream>
C++
int main()
{
    std::string bosh;
    std::string salom{"Salom"};
    std::string takror(5, 'x');
    std::string nusxa{salom};
    std::string qism{salom, 0, 3};      // 0-indeksdan 3 belgi

    std::println("bosh:    '{}' ({} belgi)", bosh, bosh.size());
    std::println("salom:   '{}' ({} belgi)", salom, salom.size());
    std::println("takror:  '{}'", takror);
    std::println("nusxa:   '{}'", nusxa);
    std::println("qism:    '{}'", qism);

    // Uzunlik O(1) - saqlanadi, hisoblanmaydi
    std::println("");
    std::println("bo'shmi:      {}", bosh.empty());
    std::println("birinchi:     {}", salom.front());
    std::println("oxirgi:       {}", salom.back());

    return 0;
}
Natija
bosh:    '' (0 belgi)
salom:   'Salom' (5 belgi)
takror:  'xxxxx'
nusxa:   'Salom'
qism:    'Sal'

bo'shmi:      true
birinchi:     S
oxirgi:       m

Satrlarni birlashtirish va o'zgartirish #

C++
int main()
{
    std::string matn{"Salom"};

    matn += ", ";
    matn += "dunyo";
    matn.push_back('!');

    std::println("qo'shgandan keyin: {}", matn);

    matn.insert(0, ">> ");
    std::println("boshiga qo'shildi: {}", matn);

    matn.replace(3, 5, "Assalom");
    std::println("almashtirildi:     {}", matn);

    matn.erase(0, 3);
    std::println("boshi o'chirildi:  {}", matn);

    std::println("");
    std::println("katta harflarda:");
    std::string katta = matn;
    std::ranges::transform(katta, katta.begin(),
                           [](unsigned char c) { return std::toupper(c); });
    std::println("  {}", katta);

    return 0;
}
Natija
qo'shgandan keyin: Salom, dunyo!
boshiga qo'shildi: >> Salom, dunyo!
almashtirildi:     >> Assalom, dunyo!
boshi o'chirildi:  Assalom, dunyo!

katta harflarda:
  ASSALOM, DUNYO!

Qidirish #

C++
int main()
{
    std::string matn{"Husanboy Qodirov, Namangan shahri"};

    auto orin = matn.find("Qodirov");
    std::println("'Qodirov' o'rni: {}", orin);

    auto yoq = matn.find("Toshkent");
    std::println("'Toshkent' topildimi: {}",
                 yoq == std::string::npos ? "yo'q" : "ha");

    std::println("");
    std::println("boshlanadi 'Husanboy' bilan: {}",
                 matn.starts_with("Husanboy"));     // C++20
    std::println("tugaydi 'shahri' bilan:      {}",
                 matn.ends_with("shahri"));
    std::println("'Namangan' bormi:            {}",
                 matn.contains("Namangan"));        // C++23

    // Barcha vergullarni topish
    std::println("");
    std::size_t joy = 0;
    int soni = 0;
    while ((joy = matn.find(',', joy)) != std::string::npos) {
        ++soni;
        ++joy;
    }
    std::println("vergullar soni: {}", soni);

    return 0;
}
Natija
'Qodirov' o'rni: 9
'Toshkent' topildimi: yo'q

boshlanadi 'Husanboy' bilan: true
tugaydi 'shahri' bilan:      true
'Namangan' bormi:            true

vergullar soni: 1
npos - "topilmadi" belgisi

find topa olmasa std::string::npos qaytaradi. Bu eng katta size_t qiymati.

Tuzoq: npos ni -1 bilan solishtirish yoki int ga solish - xato:

KOD
int orin = matn.find("x");        // XATO: npos int ga sig'maydi
if (orin >= 0) { ... }            // har doim rost

To'g'ri:

KOD
auto orin = matn.find("x");
if (orin != std::string::npos) { ... }

auto bu yerda ham foydali - u to'g'ri turni o'zi tanlaydi.

std::string_view - nusxasiz ko'rinish #

C++
// Nusxa oladi
std::size_t nusxaBilan(std::string matn)
{
    return matn.size();
}

// Nusxa olmaydi, lekin faqat std::string qabul qiladi
std::size_t havolaBilan(const std::string& matn)
{
    return matn.size();
}

// Nusxa olmaydi va HAMMA narsani qabul qiladi
std::size_t korinishBilan(std::string_view matn)
{
    return matn.size();
}

int main()
{
    std::string s{"Husanboy Qodirov"};
    const char* c = "C uslubidagi satr";

    std::println("std::string bilan:");
    std::println("  nusxaBilan:      {}", nusxaBilan(s));
    std::println("  havolaBilan:     {}", havolaBilan(s));
    std::println("  korinishBilan:   {}", korinishBilan(s));

    std::println("");
    std::println("const char* bilan:");
    std::println("  nusxaBilan:      {}  <- vaqtinchalik string yasaldi",
                 nusxaBilan(c));
    std::println("  havolaBilan:     {}  <- vaqtinchalik string yasaldi",
                 havolaBilan(c));
    std::println("  korinishBilan:   {}  <- nusxa YO'Q", korinishBilan(c));

    std::println("");
    std::println("string_view hajmi: {} bayt", sizeof(std::string_view));
    std::println("string hajmi:      {} bayt", sizeof(std::string));

    return 0;
}
Natija
std::string bilan:
  nusxaBilan:      16
  havolaBilan:     16
  korinishBilan:   16

const char* bilan:
  nusxaBilan:      17  <- vaqtinchalik string yasaldi
  havolaBilan:     17  <- vaqtinchalik string yasaldi
  korinishBilan:   17  <- nusxa YO'Q

string_view hajmi: 16 bayt
string hajmi:      32 bayt
string_view nima

std::string_view - ikkita narsadan iborat: ko'rsatkich va uzunlik. U hech narsaga egalik qilmaydi.

std::stringstd::string_view
Xotira egallaydimiHaYo'q
Nusxalash narxiButun matn16 bayt
O'zgartirishMumkinMumkin emas
Nol bilan tugaydimiHaKafolat yo'q
EgalikBorYo'q

Amaliy qoida:

Funksiya satrni faqat o'qisa - std::string_view. Satrni saqlab qolsa - std::string.

Oxirgi qator muhim: string_view ni sinf a'zosi sifatida saqlash xavfli - ko'rsatilayotgan matn yo'q bo'lishi mumkin.

string_view ning xavfi #

C++
std::string_view xatoFunksiya()
{
    std::string mahalliy{"men yo'q bo'laman"};
    return mahalliy;          // string_view osilib qoladi
}

int main()
{
    // TO'G'RI ishlatish - asl obyekt hayot davomida mavjud
    std::string manba{"Husanboy Qodirov, Namangan"};
    std::string_view toliq{manba};
    std::string_view ism = toliq.substr(0, 8);
    std::string_view familiya = toliq.substr(9, 7);

    std::println("to'liq:   {}", toliq);
    std::println("ism:      {}", ism);
    std::println("familiya: {}", familiya);
    std::println("");
    std::println("uchalasi BIR XIL xotiraga ishora qiladi -");
    std::println("hech qanday nusxa olinmadi.");

    std::println("");
    std::println("xatoFunksiya() osilgan ko'rinish qaytaradi -");
    std::println("uni ishlatish aniqlanmagan xulq-atvor.");

    return 0;
}
Natija
to'liq:   Husanboy Qodirov, Namangan
ism:      Husanboy
familiya: Qodirov

uchalasi BIR XIL xotiraga ishora qiladi -
hech qanday nusxa olinmadi.

xatoFunksiya() osilgan ko'rinish qaytaradi -
uni ishlatish aniqlanmagan xulq-atvor.
string_view umrni uzaytirmaydi

Bu 4- va 5-bo'limlardagi osilgan havola muammosining uchinchi ko'rinishi.

string_view faqat manzil va uzunlikni saqlaydi. Asl matn yo'q bo'lsa - u ishora qiladigan xotira ham yo'q.

Eng ko'p uchraydigan xatolar:

XatoNima uchun
string_view qaytarish (mahalliy satrdan)Osilgan
Sinf a'zosi sifatida saqlashManba yo'q bo'lishi mumkin
sv = std::string{"..."}Vaqtinchalik obyekt darhol o'ladi
Konteynerda saqlashManba o'zgarsa yaroqsizlanadi

Xavfsiz ishlatish:

To'g'riIzoh
Funksiya parametriChaqiruv davomida manba mavjud
Mahalliy o'zgaruvchiQamrov ichida
Doimiy satrlar bilan"matn" dastur davomida yashaydi
std::string va std::string_view std::string korsatkich · uzunlik · sig'im "Husanboy Qodirov" (o'ziniki) Xotiraga EGALIK qiladi std::string_view korsatkich · uzunlik (16 bayt) boshqa birovning xotirasi Faqat KO'RSATADI Qachon qaysi biri Faqat o'qishstring_view · Saqlab qolishstring · O'zgartirishstring& Asosiy xavf string_view asl matnning umrini uzaytirmaydi - manba yo'q bo'lsa, u osilib qoladi.
string_view - arzon, lekin egalik bermaydi

Satrni bo'laklarga ajratish #

C++
std::vector<std::string> ajrat(std::string_view matn, char belgi)
{
    std::vector<std::string> natija;
    std::size_t boshi = 0;

    while (true) {
        std::size_t orin = matn.find(belgi, boshi);

        if (orin == std::string_view::npos) {
            natija.emplace_back(matn.substr(boshi));
            break;
        }

        natija.emplace_back(matn.substr(boshi, orin - boshi));
        boshi = orin + 1;
    }

    return natija;
}

int main()
{
    auto qismlar = ajrat("Husanboy,Malika,Nodira,Aziza", ',');

    std::println("{} ta qism:", qismlar.size());
    for (const auto& q : qismlar) {
        std::println("  '{}'", q);
    }

    // Bo'shliq bo'yicha
    auto sozlar = ajrat("bir ikki uch tort", ' ');
    std::println("");
    std::println("so'zlar: {}", sozlar);

    return 0;
}
Natija
4 ta qism:
  'Husanboy'
  'Malika'
  'Nodira'
  'Aziza'

so'zlar: ["bir", "ikki", "uch", "tort"]

Sonlarni satrga va aksincha #

C++
#include <charconv>

int main()
{
    // Songa aylantirish - eski usul
    std::string matn{"12345"};
    int son = std::stoi(matn);
    double kasr = std::stod("3.14159");

    std::println("stoi:  {}", son);
    std::println("stod:  {}", kasr);

    // Satrga aylantirish
    std::println("to_string:  {}", std::to_string(42));
    std::println("format:     {}", std::format("{:.3f}", 3.14159));
    std::println("format:     {}", std::format("{:>10}", "o'ngga"));
    std::println("format:     {}", std::format("{:08.2f}", 3.14159));
    std::println("format:     {}", std::format("{:#x}", 255));

    // Xato holatlari
    std::println("");
    try {
        std::stoi("bu son emas");
    } catch (const std::invalid_argument& x) {
        std::println("stoi xatosi: {}", x.what());
    }

    // Zamonaviy usul - istisnosiz
    std::string_view kiritma{"789xyz"};
    int natija{};
    auto [oxiri, xato] = std::from_chars(kiritma.data(),
                                         kiritma.data() + kiritma.size(),
                                         natija);

    std::println("");
    std::println("from_chars: {} (qolgan qism: '{}')",
                 natija, std::string_view{oxiri});

    return 0;
}
Natija
stoi:  12345
stod:  3.14159
to_string:  42
format:     3.142
format:         o'ngga
format:     00003.14
format:     0xff

stoi xatosi: stoi

from_chars: 789 (qolgan qism: 'xyz')
std::format - qulay formatlash

{} ichiga formatlash ko'rsatmalari yoziladi:

YozuvMa'nosi
{:.3f}Kasr, 3 raqam
{:>10}O'ngga tekislash, 10 kenglik
{:<10}Chapga
{:^10}O'rtaga
{:08.2f}Nol bilan to'ldirish
{:#x}O'n oltilik, 0x prefiksi bilan
{:b}Ikkilik
{:+}Ishorani doim ko'rsatish

std::format va std::println bir xil sintaksisdan foydalanadi.

Muhim: format satri kompilyatsiya paytida tekshiriladi. Argument soni yoki turi mos kelmasa - kompilyatsiya xatosi. printf da esa bu ish vaqtidagi buzilishga olib kelardi.

Satrlarni solishtirish #

C++
int main()
{
    std::string a{"olma"};
    std::string b{"anor"};

    std::println("a == b:  {}", a == b);
    std::println("a < b:   {}", a < b);
    std::println("a > b:   {}", a > b);

    // C++20 - uch tomonlama solishtirish
    auto natija = a <=> b;
    std::println("");
    std::println("a <=> b: {}",
                 natija < 0 ? "kichik" : (natija > 0 ? "katta" : "teng"));

    // Tartiblash lug'at tartibida
    std::vector<std::string> mevalar{"uzum", "olma", "anor", "behi"};
    std::ranges::sort(mevalar);
    std::println("");
    std::println("tartiblangan: {}", mevalar);

    // Registrga sezgir emas solishtirish
    auto tengmi = [](std::string_view x, std::string_view y) {
        return std::ranges::equal(x, y, [](unsigned char c1, unsigned char c2) {
            return std::tolower(c1) == std::tolower(c2);
        });
    };

    std::println("");
    std::println("'Olma' va 'olma' teng: {}", tengmi("Olma", "olma"));

    return 0;
}
Natija
a == b:  false
a < b:   false
a > b:   true

a <=> b: katta

tartiblangan: ["anor", "behi", "olma", "uzum"]

'Olma' va 'olma' teng: true
Solishtirish baytlar bo'yicha boradi

std::string UTF-8 ni bilmaydi. U baytlarni solishtiradi.

Oqibatlari:

AmalO'zbek matni bilan
.size()Baytlar soni, harflar emas
[i]i-bayt, i-harf emas
< solishtirishLug'at tartibi emas
toupperFaqat ASCII harflar uchun

Masalan "o'g'il" da apostroflar bilan birga 7 bayt bor, lekin harflar soni boshqa.

Kirill yoki maxsus belgilar bilan ishlaganda bu farq kattaroq bo'ladi.

To'liq Unicode qo'llab-quvvatlash uchun alohida kutubxona kerak (ICU va h.k.). Standart kutubxonada bu yo'q.

Amaliy holat: saqlash va uzatish uchun std::string mukammal ishlaydi. Muammo faqat harflarni sanash va tartiblashda paydo bo'ladi.

Kichik satr optimallashtirishi #

C++
int main()
{
    std::println("std::string hajmi: {} bayt", sizeof(std::string));
    std::println("");

    std::string qisqa{"salom"};
    std::string uzun{"bu satr kichik satr optimallashtirishiga sig'maydi"};

    std::println("qisqa: {} belgi, sig'im {}", qisqa.size(), qisqa.capacity());
    std::println("uzun:  {} belgi, sig'im {}", uzun.size(), uzun.capacity());

    std::println("");
    std::println("Qisqa satrlar obyektning O'ZIDA saqlanadi -");
    std::println("dinamik xotira ajratilmaydi.");

    return 0;
}
Natija
std::string hajmi: 32 bayt

qisqa: 5 belgi, sig'im 15
uzun:  50 belgi, sig'im 50

Qisqa satrlar obyektning O'ZIDA saqlanadi -
dinamik xotira ajratilmaydi.
Kichik satr optimallashtirishi (SSO)

std::string 32 bayt egallaydi, lekin uning ichida ko'rsatkich, uzunlik va sig'imdan tashqari kichik bufer ham bor.

Satr yetarlicha qisqa bo'lsa (GCC da 15 belgigacha), u o'sha buferga joylashadi va dinamik xotira umuman ajratilmaydi.

Foydasi:

HolatXotira ajratish
"salom" (5 belgi)Yo'q
"Husanboy Qodirov" (16 belgi)Bor
Vaqtinchalik kalitlar, qisqa nomlarOdatda yo'q

Bu ko'p kodda std::string ni const char* bilan bir xil tezlikda ishlashini ta'minlaydi.

Aniq chegara kompilyatorga bog'liq va standartda belgilanmagan.

Amaliy topshiriq
  1. Satrni besh xil usulda yarating va uzunliklarini chiqaring.
  2. Satrga qo'shish, kiritish, almashtirish va o'chirishni sinang.
  3. find bilan qidiring va npos ni to'g'ri tekshiring.
  4. starts_with, ends_with, contains ni ishlating.
  5. Bir funksiyani string, const string& va string_view bilan yozing.
  6. Har birini const char* bilan chaqirib, farqni tushuntiring.
  7. string_view qaytaruvchi xavfli funksiya yozing.
  8. Satrni belgi bo'yicha bo'laklarga ajratuvchi funksiya yozing.
  9. std::format ning oltita formatlash ko'rsatmasini sinang.
  10. sizeof(std::string) ni o'lchang va SSO chegarasini toping.

Xulosa #

  • std::string uzunlikni saqlaydi - .size() doimiy vaqtda ishlaydi.
  • U xotirani o'zi boshqaradi: qo'shish, o'chirish, kengaytirish avtomatik.
  • find topa olmasa npos qaytaradi - uni int ga solmang.
  • C++20/23 da starts_with, ends_with, contains qo'shildi.
  • std::string_view - ko'rsatkich va uzunlik, nusxa olmaydi.
  • Faqat o'qiydigan parametrlar uchun string_view, saqlash uchun string.
  • string_view asl matnning umrini uzaytirmaydi - osilib qolishi mumkin.
  • std::format format satrini kompilyatsiya paytida tekshiradi.
  • Solishtirish baytlar bo'yicha boradi - UTF-8 harflari bilan ehtiyot bo'ling.
  • Kichik satr optimallashtirishi qisqa satrlar uchun xotira ajratmaydi.

Keyingi bo'limda konteynerlar bilan tanishamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.