Jak snadno pracovat

s řetězci?

Řetězce a znaky aneb všechno jsou to čísla

Hned ve druhé úloze domácího kola 2016 narazíš na práci s textem. Ničeho se ale neboj. Jak tento návod (snad :) ) ukáže, tak poradit si s ním nebude - nezávisle na zvoleném programovacím jazyce - nic těžkého.

Co jsou to řetězce

Vedle možnosti pamatovat si v průběhu programu čísla (normální číselné proměnné) naprostá většina programovacích jazyků nabízí i prostředky, jak si zapamatovat kus textu. A jeden takový zapamatovaný kus textu se obecně nazývá textový řetězec.

Počítače ale samozřejmě nic jako text nechápou. Řetězce proto berou jako pole znaků. A znaky? Znaky jsou jako všechno v počítačích prostě čísla.

Pomineme-li hodně zajímavých, ale pro naše úlohy naprosto zbytečných, složitostí ohledně různých kódování (mapování znaků na čísla), tak si můžeme představit, že pro anglickou abecedu (a několik normálních znaků jako čárky tečky a tak) platí následující. Jeden znak - jak jej chápe počítač - vždy odpovídá znaku, jak jej chápeme i my.

Pro znaky mimo anglickou abecedu je situace trochu složitější. V závislosti na kódování může být jedno písmeno jak jej chápeme my složené klidně z několika znaků, jak jej bude chápat většina programovacích jazyků. To je ovšem zas něco mimo náš rozsah.

Řetězce jako čísla

Řetězec "Ahoj petre." tedy většina programovacích jazyků chápe jako pole čísel, kde první hodnota odpovídá číselné reprezentaci písmena "A", druhé reprezentaci "h", a tak dále.

V některých jazycích (například C-čku) odpovídá poli ve skutečnosti o jedna delším než původní text. Poslední znak je pak takzvaná ukončovací nula, aby bylo poznat, kde řetězec v paměti končí.

V jiných (třeba C#, Java, Python) řetězec zas není čisté pole, ale nějaká složitější struktura, která si svojí délku pamatuje někde vedle.

To je ovšem zase detail, který pro naše potřeby není důležitý. Nám bohatě stačí, že řetězec z písmen anglické abecedy, odpovídá poli čísel. A ne ledajakých čísel. Prakticky vždy se můžeme spolehnout, že písmeno 'b' bude odpovídat číslu o jedna vyšším než písmeno 'a'. Stejně tak písmeno 'Z' číslu o 25 větším než 'A'.

O moc víc logiky v kódování bohužel nenalezneme. Už tak nemusí platit, že na sebe třeba čísla velkých a malých písmen navazují.

Ukázky v programovacích jazycích

Pro zjištění jestli je např. třetí znak ze vstupu písmeno anglické abecedy a pokud je, tak vypsání znaku těsně následujícím, musíme udělat takového:

C#
string nasRetezec = Console.ReadLine();
char nasZnak = nasRetezec[2];
byte cisloNasehoZnaku = (byte)nasZnak;

byte cislo_a = (byte)'a';
byte cislo_z = (byte)'z';
byte cislo_A = (byte)'A';
byte cislo_Z = (byte)'Z';

if ((cisloNasehoZnaku >= cislo_a && cisloNasehoZnaku <= cislo_z) ||
		(cisloNasehoZnaku >= cislo_A && cisloNasehoZnaku <= cislo_Z))
{
	Console.WriteLine((char)(cisloNasehoZnaku + 1));
}
Python3
nasRetezec = input()

nasZnak = nasRetezec[2]
cisloNasehoZnaku = ord(nasZnak)

cislo_a = ord('a')
cislo_z = ord('z')
cislo_A = ord('A')
cislo_Z = ord('Z')

if (cisloNasehoZnaku >= cislo_a and cisloNasehoZnaku <= cislo_z) 
		or (cisloNasehoZnaku >= cislo_A and cisloNasehoZnaku <= cislo_Z):
	print(chr(cisloNasehoZnaku + 1))	
C++
#include <string>
#include <iostream>
using namespace std;

...

string nasRetezec;
getline(cin, nasRetezec); 

char nasZnak = nasRetezec[2];

if ((nasZnak >= 'a' && nasZnak <= 'z') || (nasZnak >= 'A' && nasZnak <= 'Z'))
	cout << (char) (nasZnak + 1) << endl;
C
size_t n = 0;
char * nasRetezec = NULL, nasZnak;

if (getline(&nasRetezec, &n, stdin) > 2) {
	nasZnak = nasRetezec[2];
	
	if ((nasZnak >= 'a' && nasZnak <= 'z')
			|| (nasZnak >= 'A' && nasZnak <= 'Z'))
		printf("%c\n", nasZnak + 1);
}

free(nasRetezec);

Pozn.: V některých jazycích (třeba C#) je explicitní převod ze znaku na číslo zbytečný. Znaky v nich totiž jdou s čísly porovnávat přímo (např. `’a’ < ‘c’` či `’a’ < 100`) a někdy je možné je přičtením čísla bez explicitního přetypování i posunout. Tím, že do kódu převod napíšete přímo ale nikdy nic nezkazíte.

Máš na to!

I ty můžeš vyhrát! Nebo to aspoň zkusit :)