String - teksty

W JavaScript tak samo jak w innych językach możemy operować nie tylko na liczbach, ale także na tekstach. Tak zwane stringi w JavaScript możemy tworzyć na kilka sposobów:


const text = "Ala ma kota, a kot ma Ale."; //podwójne cudzysłowy

//lub

const text = 'Ala ma kota'; //pojedyncze apostrofy

Kiedy którego używać? W zasadzie wybór zależy od naszych preferencji, chociaż zdarzają się przypadki, że dany zapis może być ciut wygodniejszy od swojego brata:


//dzięki temu że zacząłem string od pojedynczych apostrofów
//bez problemu pisałem w środku cudzysłowy
const img = '<div class="element" data-text="test">';

//no to w drugą stronę
const txt = "It's a big year";

//ale w sumie nie ma to aż takiego znaczenia, bo zawsze możemy użyć znaku ucieczki
const img = "<div class=\"element\" data-text=\"test\">";
const txt = 'It\'s a big year';

Od 2015 roku stringi możemy też tworzyć za pomocą tak zwanych template string używając przy tym backticków:


const text = `Ala ma kota`;

Ich główną przewagą nad klasycznymi braćmi jest to, że unikamy tutaj problemów z cudzysłowami i apostrofami wewnątrz tekstu (ale już pisząc w ich wnętrzu backticki musimy stosowac znak ucieczki), ale przede wszystkim bez problemu możemy tutaj pisać teksty na kilka linii, oraz o wiele łatwiej możemy wstawiać do tekstu zmienne. Ale to za chwilę...

Teksty na wiele linii

Domyślnie klasyczne stringi tworzone za pomocą apostrofów lub cudzysłowów mogą być pisane tylko w jednej linii. Tworząc wieloliniowe teksty możemy zastosować kilka technik.


//poprzez operator przypisania
let text = "Stoi na stacji lokomotywa,<br>";
text += "Ciężka, ogromna i pot z niej spływa:<br>";
text += "Tłusta oliwa.";

//poprzez dodawanie części tekstu
let text = "Stoi na stacji lokomotywa,<br>"
+ "Ciężka, ogromna i pot z niej spływa:<br>"
+ "Tłusta oliwa."

//Poprzez zastosowanie znaku backslash na końcu linii
let text = "Stoi na stacji lokomotywa,<br>\
Ciężka, ogromna i pot z niej spływa:<br>\
Tłusta oliwa.\
"

//Najlepsza metoda - użycie template strings
let text = `Stoi na stacji lokomotywa,<br>
Ciężka, ogromna i pot z niej spływa:<br>
Tłusta oliwa.
`

Wstawianie zmiennych do tekstu

Do wnętrza tekstu zmienne możemy wstawić na kilka sposobów. Dwa najpopularniejsze to dodawanie do stringa zmiennej oraz w przypadku template strings użycie tak zwanej interpolacji:


const age = 10;

const text = "Ten pies ma " + age + " lat";
const text = 'Ten kot ma ' + age + ' lat';
const text = `Ten chomik ma ${age} lat`;

const a = 112;
const b = 120;

const text = "Cena produktu A to " + a + "zł, cena produktu B to " + b + "zł, a suma to " + (a+b)+ "zł";
const text = `Cena produktu A to ${a}zł, cena produktu B to ${b}zł, a suma to ${a+b}zł`;

Template strings wydaje się fantastyczną sprawą. Pamiętaj tylko, że przy pisaniu takiego kodu trzeba mieć na uwadze to, że nie wszystkie przeglądarki obsługują tą składnię i w razie potrzeby przydało by się konwertować taki kod na starszy zapis.

Dokładniej temat template strings omówimy w jednym z kolejnych rozdziałów.

Długość tekstu

Aby odczytać długość naszego tekstu posłużymy się właściwością length.


const text = "Ala";
text.length; //3

"Koty i psy są fajne".length //19

Przy pracy z normalnymi tekstami, właściwość length zwróci wynik jak należy.

Pobieranie znaku na danej pozycji

Do pobrania w tekście znaku na danej pozycji możemy zastosować dwa podejścia. Jedno z nich to użycie metody charAt(). Drugie - to odwoływanie się do liter tekstu jak do elementów tablicy - poprzez kwadratowe nawiasy.
Zasady są te same co przy tablicach. Pierwsza litera ma index 0, a ostatnia text.length-1


const text = "Ala ma kota, a kot ma Ale";

console.log(text.charAt(0)); //A
console.log(text.charAt(4)); //m

console.log(text[0]); //A
console.log(text[4]); //m

console.log(text.charAt(text.length-1)); //e
console.log(text[text.length-1]); //e

Typy proste (w tym String) nie są mutowalne, stąd nie możemy w nich bezpośrednio podmieniać liter jak pokazano poniżej:


const txt = "Ala ma kota";
txt[0] = "E";
console.log(txt); //"Ala ma kota"

Żeby móc podmienić literę w tekście, musimy wykorzystać dowolny sposób, który zwróci nam nowy tekst. Może to być zastosowanie replace(), substr(), czy innych opisanych na stackoverflow. Poniżej przykładowy sposób korzystający z tablicy:


const txt = "Ala ma kota";
const tab = [...txt];
tab[0] = "E";
const newTxt = tab.join("");
console.log(newTxt); //"Ela ma kota"

Metody toUpperCase() i toLowerCase()

Metody toUpperCase() i toLowerCase() służą odpowiednio do zamieniania tekstu na duże i małe litery.


const text = "Ala ma kota";

console.log(text.toUpperCase()); //"ALA MA KOTA"
console.log(text.toLowerCase()); //"ala ma kota"

Metody indexOf() i lastIndexOf()

Metoda indexOf zwraca pozycję szukanego fragmentu w tekście (ale także w tablicy, bo metoda ta dostępna jest dla stringów i tablic).
Wynik -1 oznacza, że szukanego fragmentu nie znaleziono:


"Ala ma kota".indexOf("kot"); //7

const text = "Ala ma kota";

//sprawdzamy czy ciąg "psa" istnieje
if (text.indexOf("psa") !== -1) {
    console.log("Ala ma psa");
} else {
    console.log("Ala ma kota");
}


if (~text.indexOf("psa")) {
    console.log("Ala ma psa");
} else {
    console.log("Ala ma kota");
}

Zastosowany w drugim przykładzie znak tyldy to operator bitowy. Wykonuje on działanie -(x + 1).

Zobaczmy jak zadziała dla indexOf:


        ~"lorem".indexOf("lo"); //0 ——> -(0 + 1) ——> -1 ——> true
        ~"lorem".indexOf("re"); //2 ——> -(2 + 1) ——> -3 ——> true
        ~"lorem".indexOf("kot"); //-1 ——> -(-1 + 1) —— -0 ——> 0 ——> false
    

Ciekawy artykuł na ten temat znajduje się pod adresem https://dreaminginjavascript.wordpress.com/2008/07/04/28/

Podobne działanie ma metoda lastIndexOf, podaje ona jednak numer ostatniego wystąpienia podtekstu


"Ala ma kota i tak już jest".lastIndexOf("a"); //15 - bo ostatnia litera występuje na pozycji 15

const url = "http://nazwastrony.pl/przykladowaNazwaPliku.php";

//korzystając z metod opisanych poniżej tniemy url na części
console.log( url.slice(url.lastIndexOf(".") + 1) ); //"php"
console.log( url.slice(url.lastIndexOf("/") + 1, url.lastIndexOf(".")) ); //"przykladowaNazwaPliku"

//można też ciut inaczej
const file = url.slice(url.lastIndexOf("/") + 1); //"przykladowaNazwaPliku.php"
const part = file.split("."); //dzielimy nazwę na części (otrzymujemy tablicę)
console.log( part[1] ); //"php"
console.log( part[0] ); //"przykladowaNazwaPliku"

W nowym Javascript istnieje też metoda includes(str), która także służy do wyszukiwania fragmentów tekstu. Różnica przy jej użyciu jest taka, że zamiast pozycji szukanego ciągu zwraca true/false:


const text = "Ala ma kota";

if (text.includes("psa")) {
    console.log("Ala ma psa" );
} else {
    console.log("Ala ma kota" );
}

Metody startsWith() i endsWith()

W ES6 (ECMAScript 2015) wprowadzono dwie dodatkowe funkcje - startsWith() i endsWith(), które jak sama nazwa wskazuje zwracają prawdę lub fałsz jeżeli tekst zaczyna się lub kończy od szukanej frazy:


const text = "Ala ma kota";

text.startsWith("Ala"); //true
text.startsWith("Ola"); //false

text.endsWith("kota"); //true
text.endsWith("psa"); //false

Metoda substr()

Metoda substr(start, lng) służy do zwracania kawałka tekstu. Pierwszym jej parametrem jest początek pobieranego kawałka tekstu, a drugi opcjonalny wskazuje długość pobieranego tekstu. Jeżeli drugi parametr nie zostanie podany, wówczas pobierany kawałek będzie pobierany do końca tekstu.


const text = "Ala ma kota";

console.log(text.substr(2)); //"a ma kota"
console.log(text.substr(0, 3)); //"Ala"
console.log(text.substr(7, 4)); //"kota"
console.log(text.substr(4)); //wypisze tekst od 4 litery do końca - "ma kota"

Tu też można zastosować ciekawą sztuczkę:


const txt = "Marcin ma kota i psa";

//chcę wyciąć napis "ma kota i psa";
const restText = txt.substr("Marcin".length);
console.log(restText); //" ma kota i psa";

Metoda substring()

Metoda substring(start, stop) ma bardzo podobne działanie co powyższa. Różnicą jest drugi parametr, który zamiast długości wyznacza miejsce końca pobieranego kawałka. Jeżeli drugi parametr nie zostanie podany, wtedy kawałek będzie pobierany do końca tekstu. Jeżeli zostaną podane oba parametry, ale drugi będzie mniejszy od pierwszego, wtedy automatycznie zostaną one zamienione miejscami.


const text = "Ala ma kota";

console.log(text.substring(0, 3)); //"Ala"
console.log(text.substring(3)); //"ma kota"
console.log("Ala ma kota".substring(6, 4)); //"ma"

Metoda slice()

Tekst jest uporządkowanym ciągiem znaków.
Tak samo jak w przypadku tablic, tak i w przypadku zmiennych tekstowych możemy skorzystać z metody slice(start, stop), która zwraca nam kawałek tekstu. Jej działanie jest praktycznie identyczne do działania metody substring(), jednak występują małe różnice. Jeżeli drugi argument będzie mniejszy od pierwszego, wtedy w przeciwieństwie do substring() argumenty nie zostaną zamienione miejscami.


const txt = "Ala ma kota";

const txt2 = txt.slice(0,3);
console.log(txt2); //"Ala"

const txt3 = txt.slice(1,5);
console.log(txt3); //"la m"

const txt4 = txt.slice(4,6);
console.log(txt4); //"ma"

const txt5 = txt.slice(4);
console.log(txt5); //"ma kota"

const txt6 = txt.slice(-4);
console.log("Ala już nie ma " + txt6 + ", bo kocur jej zwiał..."); //Ala już nie ma kota, bo kocur jej zwiał...

Metoda split()

Metoda split(znak, długość) zwraca tablicę, która składa się z podzielonych fragmentów tekstu. Miejsce podziału jest podawane w parametrze znak, a maksymalna ilość zwracanych elementów w parametrze długość:


const text = "Ala ma kota, a kot ma Alę, Ala go kocha, a Kot ją wcale ;("
const parts = text.split(", ");

parts.forEach(function(letter) {
    console.log(letter.toUpperCase());
});

Metoda replace()

Metoda replace(ciag_szukany, zamieniony) zwraca nowy tekst, w którym został zamieniony szukany ciąg znaków na nowy tekst.


const text = "Ala ma kota"
const textNew = text.replace("kota", "psa");

console.log(textNew); //"Ala ma psa"

Domyślnie metoda replace() wyszukuje i zamienia tylko pierwsze wystąpienie szukanego ciągu:


const text = "Ola lubi koty, Ola lubi psy";
const textNew = text.replace("Ola", "Ela");
console.log(textNew); //"Ela lubi koty, Ola lubi psy"

Aby zostały zamienione wszystkie wystąpienia szukanego ciągu, musimy zastosować wyrażenie regularne.


const text = "Ola lubi koty, Ola lubi psy";
const textNew = text.replace(/Ola/g, "Ela"); //g jak globalnie w całym tekście
console.log(textNew); //"Ela lubi koty, Ela lubi psy"

W EcmaScript 2021 dodano też dodatkową funkcję replaceAll(), która służy do zamiany wszystkich znalezionych fragmentów tekstu:


const text = "Ola lubi koty, Ola lubi psy";
const textNew = text.replaceAll("Ola", "Ela");
console.log(textNew); //"Ela lubi koty, Ela lubi psy"

Metoda repeat()

Aby powtórzyć tekst możemy posłużyć się funkcją repeat(count). Parametr count określa liczbę powtórzeń tekstu - od 0 do +nieskończoności:


const text = "kot";
console.log(text.repeat(3)); //kotkotkot
"-".repeat(10); //----------

Podobny efekt możemy też uzyskać za pomocą klasycznych pętli:


let str = "";
for (let i=1; i<=3; i++) {
    str += "kot";
}
console.log(str); //kotkotkot

Poruszanie się po tekście

Teksty i tablice w Javascript mają dużo wspólnych cech. Podobnie pobieramy tutaj długość danych elementów (length), podobnie odwołujemy się do danych składowych (przez indeks), a i wiele metod jest identyczna (slice(), indexOf(), includes() itp).

Podobnie jak w przypadku tablic po tekstach także możemy iterować:


const txt = "abecadło";

for (let i=0; i<txt.length; i++) {
    console.log(txt[i]);
}

for (const el of txt) {
    console.log(el);
}

Dodatkową możliwością iteracji jest zamiana tekstu na tablicę i wykorzystanie jednej z metod tablicowych:


const txt = "abecadło";

[...txt].forEach(function(el) {
    console.log(el);
});

txt.split("").forEach(function(el) {
    console.log(el);
});

Długość raz jeszcze

Jak sobie powiedzieliśmy powyżej, do pobrania długości tekstu używamy właściwości length.

Sprawdźmy to na prostym przykładzie:


"a".length //1
"🐶".length //2 ????

Co za dziwo?!!
Żeby zrozumieć czemu tak się dzieje, odpalmy naszego DeLoreana i zróbmy mały powrót do przeszłości. Gdy zaczynałem tworzyć strony, normą było wpisywanie znaków za pomocą bocznej klawiatury. I tak dla przykładu jeżeli chcieliśmy wpisać literkę ą, trzymając klawisz ALT wpisywaliśmy na klawiaturze numerycznej 0177, co w kodzie HTML dawało nam znak ±, a na stronie już właściwą literkę. Zabawa taka wynikała z tego, że powszechnie stosowanym kodowaniem było wtedy ISO-8859-2. Stare czasy gdy wśród edytorów królował Pajączek i podobne twory, które ułatwiały takie konwersje.

Wraz z rozwojem HTML rozpowszechnił się standard kodowania UTF, który pozwala w dzisiejszych czasach pisać nam litery normalnie wpisując je na klawiaturze. Standard UTF charakteryzuje się tym, że każdej literze przypisany jest jakiś kod. Te wszystkie kody pogrupowane są w grupy. Większość przez nas używanych znaków znajduje się w podstawowej przestrzeni (Basic Multilingual Plane) i posiada kody składające się z 4 heksadecymalnych znaków. Tablic z kodami w necie znajdziesz setki (wystarczy wpisać UTF char code) (1, 2).

W Javascript wszystkie stringi są kodowane za pomocą UTF-16. Litery w tekście możemy zapisać pisząc je na klawiaturze, ale też za pomocą odpowiadającego danemu znaku kodu UTF wpisując go na 3 różne sposoby:


console.log("\u00BC"); //¼
console.log("\u{BC}"); //¼
console.log("\xBCb"); //¼

console.log("\u00A9"); //©
console.log("\u{A9}"); //©
console.log("\xA9"); //©

Niestety wraz z rozwojem UTF, adaptacją coraz większej liczby języków a i wdrażaniem coraz wymyślniejszych znaków - pojawiły się takie, które nie mieszczą się w podstawowej powierzchni kodów (np. popularne w ostatnich czasach Emoji), a ich kod przekracza 4 cyfry.


console.log("\u{1F691}"); //🚑
console.log("\u{1F4A9}"); //💩

Każda taka ikonka może być opisana za pomocą swojego oryginalnego kodu, ale też za pomocą 2 4-znakowych kodów, które postawione obok siebie tworzą daną ikonkę (tak zwane surogatki).


console.log("\u{1F4A9}"); //💩
console.log("\uD83D\uDCA9"); //💩

console.log("\u{1F691}"); //🚑
console.log("\uD83D\uDE91"); //🚑

Sprawa jeszcze bardziej się gmatwa, jeżeli popatrzymy na emoji, które same w sobie składają się w kilku innych emoji:


"👩‍❤️‍👩" === 👩 + ❤️‍ + 👩
console.log("👩‍❤️‍👩");

Jak wstawisz sobie tą pierwszą ikonkę do edytora, spróbuj ją skasować za pomocą backspace.

Niestety idealnego 100% rozwiązania takich sytuacji nie ma. Na stackoverflow podają, by taki string zamienić na tablicę i pobierać jej długość. Ale i ta opcja nie zawsze zadziała.

Jednym z bardziej popularnych krojów używanych przez wielu programistów jest FiraCode, która zamienia niektóre znaki na odpowiednie ikony. Zasada działania jest podobna do powyższej. Gdy wpiszemy obok siebie jakieś znaki !==, zostaną one zamienione na odpowiedni znak zastępczy.

Bardzo ciekawy artykuł na te tematy znajdziesz tutaj i tutaj.

Wszelkie prawa zastrzeżone. Jeżeli chcesz używać jakiejś części tego kursu, skontaktuj się z autorem.
Aha - i ta strona korzysta z ciasteczek.