Садржај
3 Променљиве, подаци, типови
3.5 Текстуални подаци (стрингови, ниске)
4 Гранања
4.7 Гранања - разни задаци
5 Петље
5.1 Врсте петљи
5.2 Наредбе break и continue
6 Статички методи
6.4 Корист од метода
7 Низови
7.2 Низови - вежбање
8 Матрице
9 Кориснички дефинисани типови
10 Фајлови

Стринг и низ карактера

У приручнику Увод у програмирање у програмском језику C# прочитајте поглавље 7.6 (стране 197-206).


Стринг је специфичан тип података, који по својим особинама донекле личи, али се и разликује од свих осталих типова.

Стрингове смо до сада користили скоро искључиво као атомичне (целовите, нерастављиве) податке, то јест исто као што користимо целобројне или реалне променљиве. На пример, уобичајени начин употребе целих бројева изгледа овако:

int a = 4, b = 5;
int c = a + b;
Console.WriteLine(c);

а на исти начин је могуће користити и стрингове:

string a = "programski ", b = "jezik";
string c = a + b;
Console.WriteLine(c);

Сада ћемо упознати особине стрингова по којима они много више личе на низове.

Приступ појединим карактерима стринга

У многим случајевима стринг можемо да користимо на исти начин као и низ. На пример, без обзира на то да ли променљиву s декларишемо овако:

char[] s = { 'Z', 'd', 'r', 'a', 'v', 'o' };

или овако:

string s = "Zdravo";

у наставку програма можемо да пишемо

Console.WriteLine("Broj karaktera u datoj kolekciji je {0}.", s.Length);
Console.Write("Ti karakteri su: " + s[0]);
for(int i = 1; i < s.Length; i++)
    Console.Write(", " + s[i]);
Console.WriteLine(".");

int n = 0;
foreach (char c in s)
    if (c == 'a') n++;
Console.WriteLine("Slovo 'a' se u kolekciji pojavljuje {0} puta.", n);

и у оба случаја добијамо резултат

Broj karaktera u datoj kolekciji je 6.
Ti karakteri su: Z, d, r, a, v, o.
Slovo 'a' se u kolekciji pojavljuje 1 puta.

Неизменљивост стринга

Најважнија разлика између стринга и низа карактера је у томе што елементи стринга могу само да се читају, а не и да се мењају. Због тога би наредба

s[0] = 'z';

у случају низа карактера s била нормално извршена, док у случају стринга s иста „наредба” у ствари представља синтаксну грешку. Дакле, сам језик C# не допушта могућност мењања појединих елемента или делова стринга, онако како то радимо са низом. Разлози за ово ограничење су повезани са начином на који се кодирају Unicode карактери, то јест са чињеницом да кодови појединих карактера не морају да буду исте дужине.

Ову особину стрингова зовемо неизменљивост, или имутабилност (енгл. immutable - неизменљив). Стрингу се (наравно) може додељивати нова вредност, што смо и до сада чинили, али то није у сукобу са тврдњом да је једном формиран стринг неизменљив. Додељивање вредности стрингу значи формирање новог стринга, а не преправљање постојећег, мада то није увек очигледно. На пример, ако за неки стринг recenica напишемо

recenica += '!';

то је само поједностављен начин писања (такозвани синтаксни шећер ) пуног облика наредбе

recenica = recenica + '!';

Ово су два записа исте наредбе (и значење и начин извршавања су потпуно исти), а из пуног облика се јасније види да се овом наредбом мења стринг као целина.

Погледајмо поново пример игре погађања речи из Приручника (стр. 198-199). Када играч који погађа реч унесе слово, то слово се пореди са свим словима задате речи. Пошто се слова запамћена у задатој речи не мењају током рада програма, ову реч можемо да чувамо као стринг (променљива rec у програму). Са друге стране, карактери полу-погођене речи се потенцијално ажурирају након сваког покушаја погађања. Због тога полу-погођену реч не можемо да чувамо у стрингу већ за њу користимо низ карактера skrivenaRec.

Формирање новог стринга у принципу значи алоцирање новог простора и преписивање карактера у тај нови простор (интелигентна имплементација стрингова само у изузетним случајевима успева да избегне ове споре операције). Зато треба избегавати често формирање нових стрингова, поготово ако су они веома дугачки. Следећа лекција се бави различитим начинима трансформисања стрингова без сувише честог формирања нових стрингова.

Стринг као референцирани тип

Стринг је, као и низ, референцирани тип података. Због тога, поред могућности индексирања, стрингови имају још неке заједничке особине са низовима:

  • простор за садржај стринга се заузима у динамичкој меморији

  • додељивање стринга стрингу попут s1 = s2; је додељивање референце (након доделе s1 и s2 користе исту меморију)

  • када је стринг аргумент метода, он се преноси као референца (без копирања садржаја), па позвани метод преко добијене референце приступа истој меморији као и позивајући метод

Када током одређене употребе неког стринга немамо потребе да га мењамо, методи су ефективан начин да се та употреба стринга издвоји у засебну целину.

Пример - испис стања у игри судоку

Тренутно стање у игри судоку представљено је стрингом од 81 карактера. То стање се може приказати у облику табеле, као што је учињено у методу IspisiTablu у следећем програму.

Исписана тебела изгледа овако:

+---+---+---+
|.71|..4|...|
|...|298|1..|
|.2.|..7|..3|
+---+---+---+
|64.|8..|379|
|.1.|...|.4.|
|789|..5|.12|
+---+---+---+
|4..|9..|.3.|
|..7|416|...|
|...|7..|86.|
+---+---+---+

Погледајмо сада и неке особине стринга, по којима се он као референцирани тип разликује од низа.

Мада су и низ и стринг референцирани типови, оператор == није изведен на исти начин за низове и стрингове. Као што знамо, код низова == значи поређење референци. Код стрингова су творци језика C# узели у обзир двојаку природу стрингова и одлучили да == за стрингове значи поређење садржаја. Ово има смисла не само зато што стрингове доживљавамо и као целине (док су низови пре свега колекције), него и зато што због неизменљивости стрингова није ни битно да ли су два стринга са једнаким садржајем исти или различити као референце.

Постоји и једна, више субјективна разлика између стринга и низа као референцираних типова, мада формалне разлике у том делу нема. Као што знамо, низ често модификујемо тако што мењамо вредности његових елемената, а стринг мењамо искључиво формирањем целог новог стринга. Због тога различито доживљавамо могућности над низом и стрингом, који су аргументи метода.

На следећем примеру ћемо објаснити о чему је реч:

Програм приликом извршавања исписује само Zdravo (без узвичника). То се догађа зато што се из метода DodajUzvicnik формира нови стринг и аргумент str се преусмерава на меморијску локацију која садржи тај нови стринг. Тиме се не утиче на оригинални стринг s, који из позивајућег метода и даље референцира оригинални стринг.

Да би метод DodajUzvicnik могао да промени вредност стринга, потребно је или користити реч ref испред аргумента:

static void DodajUzvicnik(ref string str) { str += '!'; }

// ...

DodajUzvicnik(ref s);

или написати метод коме је стринг повратна вредност:

static string DodajUzvicnik(string str) { return str + '!'; }

// ...

s = DodajUzvicnik(s);

Иако оваква употреба стрингова делује другачије од онога што радимо са низовима, аналогија у понашању референци је потпуна. Прва верзија метода

// ovo ne radi
static void DodajUzvicnik(string str) { str += '!'; }

не функционише из истог разлога као и метод

// ni ovo ne radi
static void NapraviNoviNiz(int[] a) { a = new int[10]; }

То што низ a (тј. његове елементе) можемо да модификујемо у методу NapraviNoviNiz, а стринг str не можемо у методу DodajUzvicnik је последица неизменљивости стрингова, а не неке разлике у понашању референци (разлике у понашању референци нема). Када хоћемо да низу из метода доделимо нову меморију, потребно је да користимо реч ref или out испред аргумента или да низ буде повратна вредност метода, баш као и са стринговима:

static void NapraviNoviNiz(ref int[] a) { a = new int[10]; }

// ...

NapraviNoviNiz(ref a);

или

static int[] NapraviNoviNiz() { return = new int[10]; }

// ...

a = NapraviNoviNiz();

Приметимо да је (као и код низова) коришћење речи ref и out код аргумената типа стринг у пракси ретко и неуобичајено. Уместо тога, врло је честа пракса да стринг формиран у методу буде повратна вредност тог метода. Подсетимо се метода Substring, Insert, Remove, PadLeft, PadRight, ToLower, ToUpper, Trim, TrimEnd, TrimStart који служе за различита трансформисања стринга. Ни један од њих не мења оригинал, а свима им се трансформисани стринг јавља као повратна вредност. Када желимо да трансформишемо оригинални стринг користећи неки од ових метода, пишемо наредбу облика s = s.f(…), где је f дати метод (уместо такчица треба навести одговарајуће аргументе).

(Created using Swinx, RunestoneComponents and PetljaDoc)
© 2022 Petlja
A- A+