уторак, 19. јануар 2016.

Rad sa stringovima u C# programskom jeziku


Još od prvog posta posvećenom C# programskom jeziku, mi konstantno koristimo stringove. Njihova upotreba u kodiranju je toliko česta čak i kad ne koristite ni delimično sve mogućnosti manipulacije sa stringovima. String u C# programskom jeziku vam je instanca klase System.String koja predstavlja tekst kao nepromenjivu sekvencu Unicode karaktera. Svaki karakter u stringu je Unicode simbol; ključna reč string sa kojom deklarišemo promenjive tipa string je samo alias klase System.String.

string link = "www.manuelradovanovic.com";
String link = "www.manuelradovanovic.com";
System.String link = "www.manuelradovanovic.com";

Sve tri navedene deklaracije su vam iste. Ono što je bitno da upamtite da je string referentni tip podataka. Pre inicijalizacije tip string ima vrednost null.



( Svaki karakter u stringu je Unicode simbol )

Često će te čuti da je string kao i niz tipa char; sličnost definitivno postoji, indeksiranje počinje od 0 ali ovo definitivno neće raditi jer karakteri ne mogu biti modifikovani kao u nizovima.

link[0] = 'M'; // error

Međutim, ovo hoće:

char[] alphabet = new char[18];
alphabet[0] = link[4]; // Output: m

Klasa String jednostavno tretira stringove kao niz char ali read-only. Vi možete dodeliti vrednost tipu string, dodeliti mu neku vrednost niza tipa char ili dodeliti mu neku vrednost tipa string.

string link = "www.manuelradovanovic.com";
char[] alphabets = { 'M', 'a', 'n', 'u', 'e', 'l' };
link = new string(alphabets);
string name = link;

Ali za manipulisanje karakterima u stringu, to možete jedino implicitno preko metoda klase String. Jednom kad deklarišete i dodelite vrednost promenjivoj tipa string; to je nepromenjivo! Zato kad vi dodelite ili promenite neku drugu vrednost promenjivoj tipa string vi u stvari stvarate novi string u memoriji dok samo imate utisak da je vaš string promenio vrednost. Vaš stari string će biti uklonjen čim to ustanovi sakupljač otpadaka, dok vi vidite vrednost novog stringa. Ukoliko nameravate u vašem programu da mnogo manipulišete stringovima onda vam je bolje koristiti klasu StringBuilder i radi brzine i radi memorije da vaša aplikacija nebi imala ozbiljne komplikacije sa performansama.

Koje se metode najčešće koriste za manipulaciju stringovima?



Ja lično mislim, da se od svih metoda klase String se najviše koristi read-only metoda Lenght koja predstavlja dužinu stringa. To naravno zavisi od toga šta hoćete da radite sa stringovima. Klasa String sadrži veliki broj metoda koji služe za obavljanje jednostavnih zadataka poput zamene karaktera, uklanjanje praznog prostora ili menjanje malih u velika slova i obratno. Pogledajte značenje nekih od najvažnijih metoda u klasi String:

  • Compare – Poredi sadržaj stringova uzimajući u vidu lokalnost tj. kulturu.
  • CompareOrdinal – Poredi sadržaj stringova ne uzimajući u obzir lokalnost tj. kulturu.
  • Copy – Kopira u novi string vrednost drugog stringa.
  • Equals – proverava da li dva stringa imaju istu vrednost.
  • Format – Formatira stringove različitih vrednosti i specifikatore formata.
  • IndexOf – Pronalazi prvi karakter ili prvo pojavljivanje podstringa.
  • IndexOfAny – Pronalazi prvo pojavljivanje bilo kog iz skupa karaktera u stringu.
  • LastIndexOf – Pronalazi zadnji karakter ili zadnje pojavljivanje podstringa.
  • LastIndexOfAny – Pronalazi zadnje pojavljivanje bilo kog iz skupa karaktera u stringu.
  • PadLeft – Dopunjava string dodajući određeni karakter koliko puta odredite na početak stringa.
  • PadRight – Dopunjava string dodajući određeni karakter koliko puta odredite na kraj stringa.
  • Remove – Briše određeni broj karaktera od navedene pozicije u stringu.
  • Replace – Zamenjuje pojavljivanje određenih karaktera ili podstringova.
  • Split – Deli string na niz podstringova na mestima gde se navedeni karakter nalazi.
  • Substring – Vraća podstring od navedene pozicije u stringu.
  • ToLower – Sva slova u stringu pretvara u mala slova.
  • ToUpper – Sva slova u stringu pretvara u velika slova.
  • Trim – Uklanja praznine i sa leve i sa desne strane stringa.
  • TrimStart – Uklanja praznine sa početka stringa.
  • TrimEnd – Uklanja praznine sa kraja stringa.
  • Itd.
Da bi ste najlakše i najbolje naučili kako da koristite ove metode neophodno je da se sami na programerski način kodiranjem igrate sa stringovima. To jest da ih menjate kako vama odgovara. Pogledajte sledeći kod programa. Taj kod menja link ovog bloga u moje ime i prezime koristeći razne metode klase String samo da bi prezentovao kako se koriste neke od metoda, da bi zatim i od mog imena i prezimena ponovo napravio link. Manipulacije sa stringovima će te inače najčešće koristiti kada pravite na primer neki gramatički program za neki strani jezik koji menja imenice i prideve prema padežima i slično. Tada će te praviti i vaše vlastite metode da bi ste skratili postupak korišćenja više metoda. Za sada dobro analizirajte kod programa i pokušajte da i vi nešto slično kodirate na vašu ruku.

using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringClass
{
    class Program
    {
        static void Main(string[] args)
        {
            // declaration and adding value to the string type
            string link = "www.manuelradovanovic.com";

            // line of 20 characters like as '-'
            string lines = new String('-', 20);

            // this declarations are the same like as the empty string declarations too
            String firstName = "";
            System.String lastName = String.Empty;

            // for the string concatenation use operator +
            // it's not the good practice if you do it in the loop
            WriteLine("String variable: " + link);

            WriteLine(lines + Environment.NewLine);

            // lenght of the string variable link
            WriteLine("Lenght of variable: " + link.Length);

            // remove 4 characters from the index 0
            link = link.Remove(0, 4);
            WriteLine("Remove 4 characters from 0: " + link);

            // remove the last 4 characters
            link = link.Remove(link.Length - 4, 4);
            WriteLine("Remove the last 4 characters: " + link);

            // replace 'r' with ' r'
            link = link.Replace("r", " r");
            WriteLine("Replace 'r' with ' r' characters: " + link);

            // split words
            string [] twoWords = link.Split(' ');
            firstName = twoWords[0];
            lastName = twoWords[1];
            WriteLine("Split words: " + firstName + " and " + lastName);
                       
            WriteLine(Environment.NewLine + lines + Environment.NewLine);
           
            // show the first and last name to upper of first letters 
            firstName = firstName.Substring(0, 1).ToUpper() + firstName.Substring(1);
            lastName = lastName.Substring(0, 1).ToUpper() + lastName.Substring(1);
                
            WriteLine("First Name: " + firstName);
            WriteLine("Last Name: " + lastName);

            WriteLine(Environment.NewLine + lines + Environment.NewLine);

            // Compare first name with 'manuel' - case-sensitive
            if (String.Compare(firstName, "manuel", false) == 0)
            {
                WriteLine("Compare first name with 'manuel' - case-sensitive: True");

            }
            else
            {
                WriteLine("Compare first name with 'manuel' - case-sensitive: False");

            }

            // Compare first name with 'manuel' - case-insensitive
            if (String.Compare(firstName, "manuel", true) == 0)
            {
                WriteLine("Compare first name with 'manuel' - case-insensitive: True");

            }
            else
            {
                WriteLine("Compare first name with 'manuel' - case-insensitive: False");

            }

            WriteLine(Environment.NewLine + lines + Environment.NewLine);

            // for the string concatenation use Concat method
            link = String.Concat(firstName, lastName);
            WriteLine("Concat method: " + link);

            // change the string link variable to lower 
            link = link.ToLower();
            WriteLine("ToLower: " + link);

            // use Join method to add www. and .com
            string[] threeWords = new string[3];
            threeWords[0] = "www";
            threeWords[1] = link;
            threeWords[2] = "com";
            link = String.Join(".", threeWords);
            WriteLine("Join: " + link);
                   
            ReadKey();

        }
    }
}

Kad pokrenete program, rezultat će biti sledeći:

String variable: www.manuelradovanovic.com
--------------------
Lenght of variable: 25
Remove 4 characters from 0: manuelradovanovic.com
Remove the last 4 characters: manuelradovanovic
Replace 'r' with ' r' characters: manuel radovanovic
Split words: manuel and radovanovic
--------------------
First Name: Manuel
Last Name: Radovanovic
--------------------
Compare first name with 'manuel' - case-sensitive: False
Compare first name with 'manuel' - case-insensitive: True
--------------------
Concat method: ManuelRadovanovic
ToLower: manuelradovanovic
Join: www.manuelradovanovic.com


Kako to sve izgleda možete pogledati i na video-u:


( C# 6.0 Tutorial - Fundamentals - 32. String Class )

Kada, kako i zašto se pored klase String koristi klasa StringBuilder?


Klasa System.Text.StringBuilder nema mnogo metoda kao klasa String ali ona radi na mnogo efikasniji način. Metode klase StringBuilder su ograničene na zamenu, dodavanje ili oduzimanje teksta od stringova. Najčešće se koristi za čitanje tekstualnih fajlova i inače kad radite sa velikom količinom stringova. Iako neki ljudi misle da je StringBuilder vrednosni tip podataka, on to nije. I StringBuilder je referentni tip podataka ali za razliku od Stringa koji predstavlja nepromenjivu sekvencu Unicode karaktera i pri svakoj operaciji kreira novi string, StringBuilder to ne radi. String alocira tačno onoliko memorije koliko je potrebno karakterima dok StringBuilder uvek dodaje više. Jednostavno dodaje novu memoriju samo ako je bafer objekta StringBuilder premali za nove podatke. Tako StringBuilder prvo alocira inicijalnu vrednost od 16 karaktera da bi je posle uvećavao za duplo ukoliko je to potrebno. Na sličan način rade i kolekcije. Naravno vi možete i sami da alocirate memoriju za StringBuilder ako to hoćete.

StringBuilder sb = new StringBuilder(20);
WriteLine(sb.Capacity); // 20

Da niste odredili alociranu memoriju na 20 karaktera, rezultat bi pokazao 16. Pogledajmo neke od najvažnijih metoda koje koristi klasa StringBuilder.

  • Append() – Dodaje string tekućem stringu.
  • AppendFormat() – Dodaje formatiran string.
  • Insert() – Ubacuje podstring u tekući string.
  • Remove() – Uklanja karaktere iz tekućeg stringa.
  • Replace() – Zamenjuje sva pojavljivanja karaktera drugim karakterom ili podstring drugim podstringom.
  • ToString() – Vraća trenutni string.
  • Itd.
Obratite pažnju na metodu ToString() koja je u stvari nadjačan metod iz klase System.Object i skoro sve klase u .Net Framework-u sadrže ToString() nadjačan metod. Možete čak i da uradite ovo:

string number = 75.ToString();

Pogledajte navedeni program koji na neki način testira brzinu dodavanja 10 000 brojeva klasi String i StringBuilder-u u milisekundama, pa se sami uverite zašto je bolje koristiti klasu StringBuilder od klase String.

using System;
using static System.Console;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringBuilderClass
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch time = new Stopwatch();
            string testString = String.Empty;
            StringBuilder testStringBuilder = new StringBuilder();

            time.Start();

            for (int i = 0; i < 10000; i++)
            {
                testString += i;

            }

            time.Stop();

            WriteLine($"Using String: {time.ElapsedMilliseconds} milliseconds.");

            time.Reset();
            time.Start();

            for (int j = 0; j < 10000; j++)
            {
                testStringBuilder.Append(j);

            }

            time.Stop();

            WriteLine($"Using StringBuilder: {time.ElapsedMilliseconds} milliseconds.");

            ReadKey();

        }
    }
}

Kad pokrenete navedeni program rezultat će biti sličan u zavisnosti od brzine rada vašeg računara i već pokrenutih memorijskih procesa na njemu.

Using String: 370 milliseconds.
Using StringBuilder: 1 milliseconds.


Kako to sve izgleda možete pogledati i na video-u:



( C# 6.0 Tutorial - Fundamentals - 33. StringBuilder vs String - Test Speed )

Formatiranje stringova

Ponekad računarski korisnici nisu zadovoljni nekim prosečnim načinom na kojem mu računar predstavlja neke vrednosti, posebno ako se te vrednosti treba da budu predstavljene i u izveštajima. Tada je neophodno formatirati vrednosti kako bi bile prilagođene čitljivosti kakvu korisnik očekuje. Na primer datum nema isti prikaz u Srbiji i u USA, može da se prikazuje na mnogobrojne načine ali prikaz datuma treba da se prikazuje kako se datum predstavlja u državi korisnika. Takođe, postoje i razni oblici prikazivanja datuma poput datuma koji prikazuje i vreme ili datuma koji prikazuje i dan u nedelji na koji datum pada ili najkraći prikaz datuma. Međutim, formatiranje stringova se ne odnosi samo na datume već i na druge mnogobrojne vrednosti poput brojeva, prikaza simbola novčani valuta, procenata ili čak da vi sami odredite kako će se neka vrednost prikazivati. Za formatiranje stringa koristite String.Format() metodu ali je možete u nekim situacijama i zaobići. Pre nego što prikažemo praktičnim primerom kako se formatiraju stringovi pogledajte neke od specifikatora stringa.
  • C – Prikaz vrednosti valute prema podešavanju formata Region-a u Control Panel-u.
  • D – Prikaz vrednosti kao celi broj
  • E – Prikaz vrednosti kao eksponencijalni broj
  • F – Prikaz vrednosti kao broj sa fiksiranim zarezom
  • G – Opšti prikaz broja
  • N – Opšti prikaz broja prema podešavanju formata Region-a u Control Panel-u.
  • P – Prikaz vrednosti kao procentualni broj
  • X – Prikaz vrednosti kao heksadecimalni zapis
  • Itd.
Sledeći program pokazuje kako se koriste specifikatori stringa kroz metodu ToString().

using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StringFormatting
{
    class Program
    {
        static void Main(string[] args)
        {
            int numberInteger = 7575;
            double numberDouble = 75.7500;

            // 07575
            WriteLine("D5 - 7575 - " + numberInteger.ToString("D5"));

            // 7.575000+E003
            WriteLine("E - 7575 - " + numberInteger.ToString("E"));

            // 1D97
            WriteLine("X - 7575 - " + numberInteger.ToString("X"));

            // 75.75 %
            WriteLine("P - (75.7500 / 100) - " + (numberDouble / 100).ToString("P"));

            // $7,575.00
            WriteLine("C - 7575 - " + numberInteger.ToString("C"));

            // 75,575.00
            WriteLine("N - 7575 - " + numberInteger.ToString("N"));

            // 75.75
            WriteLine("G - 75.7500 - " + numberDouble.ToString("G"));

            // 75.8
            WriteLine("F1 - 75.7500 - " + numberDouble.ToString("F1"));

            ReadKey();

        }
    }
}

Kad pokrenete navedeni program rezultati će biti identični.

D5 - 7575 - 07575
E - 7575 - 7.575000E+003
X - 7575 - 1D97
P - (75.7500 / 100) - 75.75 %
C - 7575 - $7,575.00
N - 7575 - 7,575.00
G - 75.7500 - 75.75
F1 - 75.7500 - 75.8


Kako to sve izgleda možete pogledati i na video-u:



( C# 6.0 Tutorial - Fundamentals - 34. String Formatting )