Java týden
Procvič si angličtinu zdarma s naším americkým e-learningem! Learn more
Pouze tento týden sleva až 80 % na celý Java e-learning!

Lekce 4 - Řetězce v Qt - QString a QChar

Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem.
Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V minulé lekci, Dokončení prvního okna v Qt a C++ - Tlačítko, jsme se posunuli v obsasti formulářových aplikací v Qt a C++ o pořádný krok dále. Uvedli jsme si problematiku layout manažerů, vložili na formulář první komponentu a naučili se také obsluhovat signály pomocí slotů. Než se pustíme do dalších okenních aplikací, bude dobré si povědět něco málo o třídě QString, která obsahuje velmi výkonné metody a není jich zrovna málo.

QString

Tato třída je schopná pracovat s unicode řetězci, které kóduje do 16-ti bitových znaků. Právě s kódováním textu má jinak C++ problém, na což jste díky tomu, že v češtině používáme háčky a čárky, asi již přišli. Pro tento účel využívá QString třídu QChar a texty ukládá jako pole QChar[].

Předně je celkem pozitivní, že QString je, na rozdíl od řetězců mnoha programovacích jazyků, mutable - tedy obsah objektu můžeme libovolně měnit, např. měnit písmena v textu. Též bych si dovolil trochu se odchýlit od C++ knihovny iostream. Protože si povídáme o Qt frameworku, budeme dnes místo něj používat textový proud na standardní výstup pomocí třídy QTextStream.

A mimo to, iostream nedokáže pracovat s Qt řetězci. Tuším, že unicode zvládá pomocí ukazatele na typ wchar_t. Sami si to můžete ověřit na tomto malém experimentu:

#include <iostream>
#include <QString>

using namespace std;

int main(int argc, char *argv[])
{
    QString text = QString("Ahoj světe! Jak se máš?");

    cout << text << endl;
}

Pokud se tento zdrojový kód pokusíte přeložit, vypadne vám následující chyba:

`Chyba: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘QString’)
cout << text << endl;
~~~~~^~~~~~~

Vytvoření projektu

Pojďme se podívat na několik prvních možností. Vytvoříme si v QtCreatoru konzolový projekt, např. s názvem retezce. Soubor main.cpp upravíme do podoby níže. Potom si podrobně projdeme jednotlivé kroky:

#include <QTextStream>
#include <QString>

int main(void) {

    QTextStream out(stdout);

    QString str = "líbí";

    str.append(" ITNetwork!!!");
    str.prepend("Mě se ");

    out << str << endl;
    out << "Retezec obsahuje " << str.count() << " znaku" << endl;

    out << str.toUpper() << endl;
    out << atr.toLower() << endl;

    return 0;
}

Nastavíme znakový proud na standardní výstup, tedy terminál/konzoli. Dále se objekt out chová velmi podobně jako knihovna iostream.

Dále vytvoříme QString proměnnou str a inicializujeme ji nějakým řetězcem: QString str = "líbí". Existuje vice možností inicializace, např. i QString str("líbí").

Protože jsem tvrdil, že tyto řetězce jsou modifikovatelné, je třeba to hned zkusit. Za původní obsah str přidáme nějaký další text pomocí a.append(" ITNetwork!!!") a abychom si předvedli sílu QString, tak zkusíme přidat i před něj nějaký text jako a.prepend("Mě se ");.

Výsledek pošleme na terminál a odřádkujeme: out << str << endl;

Další řádek bude chtít více slov. Chtěli jsme zjistit, kolik má řetězec znaků. Vhodná metoda k tomuto účelu je str.count(). Také lze použít i její ekvivalenty str.length() a str.size(), záleží na vašem zvyku a co si zapamatujete lépe.

Všimněte si, že výpis neobsahuje diakritiku a ani nemůže, protože běžný řetězec odeslaný na textový proud je vlastně ukazatel na pole typu char a nikoli QChar.

V posledních dvou řádcích pouze znaky řetězce převedeme na velká písmena pomocí out << str.toUpper() << endl a na malá jako out << atr.toLower() << endl. Zde bych chtěl upozornit, že tyto dvě metody nevrací změněný řetězec, nýbrž jeho změněnou kopii. Původní obsah se zachovává. A výsledek by měl vypadat nějak takto:

Výstup do konzole

Jak bylo výše řečeno, texty se vnitřně ukládají jako pole QChar a tedy i takto lze k datům přistupovat. Zkusme si přidat tyto dva řádky, které vypíší znak na dané pozici (snad nemusím upozorňovat, že před return 0):

out << str[0] << endl;     // M
out << str[4] << endl;     // !

Samozřejmě, existuje i metoda str.at(n), kde n je pozice znaku v řetězci počítaná od 0 do str.size() - 1.

Argumenty řetězců

Dalším pozitivem QString je, že řetězce mohou mít argumenty. Chceme-li např. vypsat text: "Na louce se prohání 15 koní.", to by problém nebyl. Ale co když se jeden kůň zaběhne do lesa. To jich na louce máme již jen 14. Nechtělo by to nějakou variabilní možnost, jak jejich počet do řetězce vložit, než takto "na pevno"? Právě k tomu nám slouží metoda str.arg(var), která funguje podobně jako např. printf() v jazyce C.

Přidáme si další řádky na ukázku:

QString kone("Na louce se prohání %1 koňů.");
int louka = 15;
out << kone.arg(louka) << endl;

Další argumenty se mohou zřetězovat stejnou metodou arg(var1).arg(var2)...:

QString kone2("Na louce se prohání %1 koňý a %2 je (jsou) v lese.");
louka = 12;
int les = 3;
out << kone2.arg(louka).arg(les) << endl;

Výsledek na terminálu je podobný tomuto:

Konzole

Pokud si přejete použít jiný typ argumentu než integer, není to problém. Dokonce na stejný řetězec můžete použít jakýkoli typ. Pravda, všechny jsem nikdy nezkoušel:

QString kone3("Kobyla má %1 hříbat a valach %2 má kobyl:-D.");
int hribe = 1;
double kobyla = 0.01;
out << kone3.arg(hribe).arg(kobyla) << endl;

A výsledek:

QStringy v C++

Práce s podřetězci

Promažeme naše ukázky až na základ a popovídáme si o dalších metodách třídy QString, určitě se vám budou líbit - vybírají podřetězce. Když jsem kdysi začínal programovat na ZX Spectru, tak právě tyto funkce mi dost chyběly... i když je bylo možno nahradit jinou konstrukcí. Jsou to metody:

  • left(n) - vrátí n znaků zleva,
  • right(n) - vrátí n znaků zprava,
  • mid(n, m) - vrátí m znaků od pozice n.

Prosím, pamatujte, že pozice se číslují od nuly.

Zkusme si opět nějaký příklad:

#include <QTextStream>
#include <QString>

int main(void) {
    QString str("Jsme ve vesmíru jediní?");

    out << str.left(4) << endl;
    out << str.right(7) << endl;
    out << str.mid(8,7) << endl;

    return 0;

Výsledek:

Konzole

Zjištění druhu znaku

Dost často se může hodit rozhodnutí, zda znak v řetězci je písmeno, číslo, bílý znak anebo něco úplně jiného. Můžeme si zkusit udělat malou analýzu textu. Qt k tomu nabízí mnoho nástrojů. Např. již jen to, že celý text je iterovatelný v cyklu, že je k dispozici přístup k jednotlivým znakům a že pro znaky jsou metody, které umí rozhodnout jaký typ znaku to je. V základu se jedná o metody isLetter() pro písmena, isDigit() pro číslice, isSpace() pro bílé znaky a isPunct() pro interpunkci, tedy tečky, čárky, vykřičníky a tak podobně.

Myslím, že nejlepší bude si to hned vyzkoušet. Budeme analyzovat jednoduchou větu a zjišťovat počty různých druhů znaků:

#include <QTextStream>
#include <QString>          // Není nutné, ale zvyk je zvyk
#include <QChar>            // Jako o řádek výše
int main(void) {

    QTextStream out(stdout);

    int pismena  = 0;
    int cisla = 0;
    int mezery  = 0;
    int intpunk  = 0;

    QString str = "Na louce se pase 1 bílý\tkůň.\n";


    // Iterace nad řetězcem
    foreach(QChar s, str) {

        if (s.isDigit()) {
            cisla++;
        }
        else if (s.isLetter()) {
            pismena++;
        }
        else if (s.isSpace()) {
            mezery++;
        }
        else if (s.isPunct()) {
            intpunk++;
        }
    }

    // Výsledek vypíšeme
    out << QString("Máme celkem %1 znaků").arg(str.count()) << endl;
    out << QString("Z toho je %1 písmen").arg(pismena) << endl;
    out << QString("pak je tam %1 čísel").arg(cisla) << endl;
    out << QString("krom toho i %1 mezer").arg(mezery) << endl;
    out << QString("a %1 znaků interpunkce").arg(intpunk) << endl;

    return 0;
}

Myslím, že zde ani není nutné toho moc vysvětlovat. Snad jen onen cyklus foreach nad QString. Prostě každý znak je QChar, který se postupně ukládá do proměnné s, dokud se nenarazí na konec textu. Po spuštění by se mohla zobrazit podobná zpráva jako níže na obrázku:

Konzole

No aby toho nebylo naráz až přespříliš, tak dnešní povídání bych ukončil a příště ještě na toto téma navázal. Řetězce se používají velmi často a proto si něco řekneme o jejich změnách, porovnávání, doplňování a určitě si ještě na něco zajímavého vzpomenu.

Děkuji za pozoronost a uvidíme se zas příště v lekci Jednoduchá kalkulačka v Qt a C++ - Layout.


 

 

Článek pro vás napsal virlupus.soft
Avatar
Jak se ti líbí článek?
1 hlasů
Autor se věnuje webovým aplikacím a skladově-účetnímu softwaru. Snaží se uvést zpět PC-Fand v Javě i Pythonu. Lexiální analýze a parserování. Studuje fyziku na MFF UK. Učil IT na střední škole.
Předchozí článek
Dokončení prvního okna v Qt a C++ - Tlačítko
Všechny články v sekci
Okenní/formulářové aplikace v Qt pro C++
Miniatura
Následující článek
Jednoduchá kalkulačka v Qt a C++ - Layout
Aktivity (4)

 

 

Komentáře

Avatar
nonsense
Člen
Avatar
nonsense:1. července 21:38

Zatím bezva.
Pokud to autor dotáhne přes sloty/signály, manipulace s komplexnějšími datovými strukturami dostupnými v Qt až k návrhovým vzorům, tak by z toho bylo vynikající komerční školení.
Už se těším, až si budu moci zaplatit.

Držím palce.

 
Odpovědět 1. července 21:38
Avatar
virlupus.soft
Redaktor
Avatar
virlupus.soft:2. července 21:13

Zdravím, chtěl bych to dotáhnout aspoň po databáze a více vláknové programovaní. Popsat aspoň základní kolekce. Vím, že Qt je šílený nástroj a snad tak v lekci číslo 500 se dostanu od základů trochu dál:-D
Nonsense, Děkuji

 
Odpovědět 2. července 21:13
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.