Hlavní navigace

GLib: Práce s řetězci (2)

Michal Burda

V minulém díle jsme začali rozebírat možnosti, které přináší knihovna GLib pro práci se standardními céčkovskými řetězci ukončenými nulovým znakem. Dnes toto povídání dokončíme. Budeme se bavit o odstraňování bílých znaků, spojování řetězců dohromady a rozdělování řetězce na pole řetězců. Látky je víc než dost, takže hurá do toho.

Odstraňování bílých znaků

Bílé znaky, anglicky white spaces, je posloupnost znaků, které nejsou vidět na obrazovce. Jsou to oddělovací znaky jako mezera, tabulátor, nový řádek a podobně. Někdy je nežádoucí, aby se v řetězci vyskytovaly (dostanou se tam třeba čtením ze souboru) a pak je nutno je odstranit. Právě k tomu slouží následující funkce.

gchar* g_strchug(gchar *string); 

…odstraní všechny bílé znaky (white spaces) ze začátku řetězce string. Zbývající znaky posune na začátek tak, aby vyplnily vzniklou mezeru. Vrátí string.

gchar* g_strchomp(gchar *string); 

…odstraní všechny bílé znaky (white spaces) z konce řetězce string. Vrátí string.

A konečně makro:

#define g_strstrip(string) 

…které odstraní všechny bílé znaky (white spaces) ze začátku i konce řetězce.

Spojování řetězců dohromady

gchar* g_strconcat(const gchar *string1, ...); 

…spojí všechny řetězce, zapsané jako argumenty funkce, dohromady. Řetězce zapisujte jako argumenty postupně za sebou v takovém pořadí, v jakém je chcete spojit. Posledním prvkem musí být vždy NULL. Výsledný, nově alokovaný řetězec funkce použije jako návratovou hodnotu. Vrácený řetězec je třeba po použití dealokovat. Vstupní řetězce zůstanou nedotčeny.

gchar* g_strjoin(const gchar *separator, ...); 

…tato funkce spojí všechny řetězce, zadané jako argumenty ..., dohromady. Mezi každé dva vloží volitelný řetězec separator. Je-li separator roven NULL, mezi řetězce se nebude vkládat nic (analogie s funkcí g_strconcat). Posledním prvkem v seznamu argumentů (řetězců) musí být NULL. Vrácený řetězec je výsledek operace sloučení. Je nově alokovaný v paměti a proto by měl být po použití dealokován.

Příklad:

/* ukazka spojovani retezcu */

#include <glib.h>

gint main(void) {
  gchar *s;

  s = g_strconcat("Toto", "je", "prvni", "retezec.", NULL);
  puts(s);
  g_free(s);
  s = g_strjoin(" ", "Toto", "je", "druhy", "retezec.", NULL);
  puts(s);
  g_free(s);

  return(0);
}

Po spuštění této malé ukázky by se na výstupu mělo objevit doslova toto:

Totojeprvniretezec.
Toto je druhy retezec.

Rozdělování řetězce na pole řetězců

GLib definuje pár funkcí zabývajících se rozdělením řetězce podle určitých kritérií na pole řetězců. První z nich je funkce:

gchar* g_strdelimit(gchar *string, const gchar *delimiters,
                    gchar new_delimiter);

…která nahradí rozdělovací znaky v řetězci string novým znakem new_delimiter. Každý znak řetězce string, který bude nalezen v řetězci delimiters, bude nahrazen znakem new_delimiter. Je-li delimiters rovno NULL, použijí se rozdělovací znaky definované jako makro  G_STR_DELIMITERS:

#define G_STR_DELIMITERS "_-|> <." 

Změny se provedou přímo v řetězci string. Funkce g_strdelimit jako návratovou hodnotu použije vstupní argument string.

Pro rozdělení řetězce podle rozdělovacího znaku na pole řetězců použijte funkci:

gchar** g_strsplit(const gchar *string, const gchar *delimiter,
                   gint max_tokens);

Tato rutina se postará o alokování pole řetězců, které předá jako návratovou hodnotu. Pole řetězců vytvoří z řetězce string tak, že jej rozdělí na maximálně max_tokens částí v místech specifikovaných řetězcem delimiter.

Každý znak řetězce delimiter bude v řetězci string chápán jako místo, kde má dojít k rozdělení. Je-li max_tokens menší než 1, rozdělí se celý řetězec. Je-li však max_tokens kladná nenulová hodnota a počet rozdělení dosáhne tohoto čísla, poslední řetězec ve vráceném poli řetězců bude obsahovat zbytek řetězce string (nezáleží na tom, že třeba ještě obsahuje nějaké rozdělovací znaky z  delimiter).

Znaky, které jsou chápány jako rozdělovací, ve výsledném poli nebudou nikdy obsaženy, ledaže bychom dosáhli max_tokens rozdělení – v takovém případě se znaky z  delimiter mohou objevit v posledním řetězci. Posledním prvkem vráceného pole je pointer s hodnotou NULL  – podle toho se také pozná konec pole.

Původní řetězec string zůstane nezměněn, takže jestliže jste ho vytvořili dynamicky, je třeba jej nakonec dealokovat – například funkcí  g_free().

K uvolnění pole řetězců vytvořeného funkcí g_strsplit() používejte:

void g_strfreev(gchar **str_array); 

…která odstraní z paměti všechny prvky pole (nulovým znakem ukončené řetězce) i samotné pole str_array.

Pro práci s poli řetězců je zde ještě jedna funkce. Její funkční prototyp je:

gchar* g_strjoinv(const gchar *separator, gchar **str_array); 

Funkce spojí řetězce, uložené v poli str_array. Je-li separator různý od NULL, vloží řetězec separator mezi každé dva spojované řetězce pole. Pole str_array musí být ukončeno NULL em (tzn. poslední prvek pole musí být NULL). Funkce vrátí nově alokovaný řetězec vytvořený spojením řetězců pole str_array.

Příklad:

/* Rozdelovani retezce na pole retezcu */

#include <glib.h>

gint main(void) {
  gchar *s, *spojeny, *pomocny;
  gchar **pole;
  gint x = 0;

  /* vytvoreni noveho retezce */
  s = g_strdup("Ahoj|jak_se_mas?");
  printf("Puvodni s = %s\n", s);

  /* nahrada oddelovacich znaku (G_STR_DELIMITERS) mezerou */
  g_strdelimit(s, NULL, ' ');
  printf("Upraveny s = %s\n", s);

  /* rozdeleni s na pole retezcu */
  pole = g_strsplit(s, " ", 0);

  /* kontrolni vypis pole */
  pomocny = pole[0];
  while (pomocny != NULL) {
    puts(pomocny);
    pomocny = pole[++x];
  }

  /* spojeni pole */
  spojeny = g_strjoinv("...", pole);
  printf("spojeny = %s\n", spojeny);

  /* dealokace */
  g_strfreev(pole);
  g_free(s);
  g_free(spojeny);

  return(0);
}

Po spuštění by se mělo vypsat:

Puvodni s = Ahoj|jak_se_mas?
Upraveny s = Ahoj jak se mas?
Ahoj
jak
se
mas?
spojeny = Ahoj...jak...se...mas?

A to je z mé strany o standardních céčkovských řetězcích vše – ale u řetězců ještě zůstaneme. Budeme si povídat o novém typu „nafukovacího řetězce“ GString, u kterého se nemusíte bát, že vám data přetečou mimo alokovanou paměť – GString se sám realokuje s přidáváním textu; ale o tom až příště.

Našli jste v článku chybu?