NOVINKA: Získej 40 hodin praktických dovedností s AI – ZDARMA ke každému akreditovanému kurzu!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze – Lekce 14 - Textové řetězce v Javě podruhé - Práce s jednotlivými znaky

Zpět

Upozorňujeme, že diskuze pod našimi online kurzy jsou nemoderované a primárně slouží k získávání zpětné vazby pro budoucí vylepšení kurzů. Pro studenty našich rekvalifikačních kurzů nabízíme možnost přímého kontaktu s lektory a studijním referentem pro osobní konzultace a podporu v rámci jejich studia. Toto je exkluzivní služba, která zajišťuje kvalitní a cílenou pomoc v případě jakýchkoli dotazů nebo projektů.

Komentáře
Avatar
Robert Michalovič:16.9.2021 7:40

Můj příspěvek ti měl vysvětlit, že to není plně tvůj problém. Jedná se hlubší problém multiplatformní Javy. Někdy je výhodné některý problém i přeskočit a vrátit se k němu mnohem později až bude mít větší znalosti.

Pro tebe bude vhodné najít správnou znakovou sadu která v tém IDE a tvém OS funguje a té se držet. Vyzkoušej tyto možnosti jednu po druhé dokud ti to nebude fungovat. Jedna ze zde zveřejněných znakových sady by ti měla pomoci, za předpokladu že máš CZ nebo ENG Windows.

Scanner sc = new Scanner (System.in, "UTF-8");
Scanner sc = new Scanner (System.in, "UTF-16");
Scanner sc = new Scanner (System.in, "cp1250");
Scanner sc = new Scanner (System.in, "cp852");
Scanner sc = new Scanner (System.in, "UTF-32");
Scanner sc = new Scanner (System.in, "ISO8859_2");
Scanner sc = new Scanner (System.in, "ISO8859_1");
Scanner sc = new Scanner (System.in, "IBM437");

Pokud to nepomůže napiš co máš za OS (např. Windows10 Pro 64bit ENG, verzi IDE + jakou jazykovou verzi, jakou verzi Javy, )

Případně můžeš zkusit vypsat jakou znakovou sadu máš defaultně nastaveno.

InputStreamReader vstup = new InputStreamReader(System.in);
System.out.println("Znakova sada nastavena vstup : "+vstup.getEncoding());
OutputStreamWriter vypis = new OutputStreamWriter(System.out);
System.out.println("Znakova sada nastavena vystup: "+vypis.getEncoding());
 
Odpovědět
16.9.2021 7:40
Avatar
Atrament
Člen
Avatar
Odpovídá na Petra Krulová
Atrament:16.9.2021 9:44

Není to nastavením, je to tím pluginem, který IDE používá ke spouštění tvého kódu, a ve kterém se zdá být momentálně nějaká chyba, že nepracuje správně se vstupem s těmi našimi krásnými znaky jako jsou č š ř a podobně.

Ověřit si to člověk může jednoduše tím, že si v Netbeans otevřeš Terminál (menu Window - IDE Tools - Terminal), přepneš se do adresáře ve kterém máš ten java soubor s programem, a prostě si ho pustíš ručně

java Soubor.java

Jednoduché prozatimní řešení je založit nový projekt, ale tentokrát nevybrat Java with Maven, ale Java with Ant. Ant funguje s českým vstupem správně.

 
Odpovědět
16.9.2021 9:44
Avatar
Odpovídá na Atrament
Petra Krulová:20.9.2021 18:03

Moc díky. V Java with Ant už to funguje jak má :-) Zatím využiju tohle řešení, v budoucnu pak jiný program.

 
Odpovědět
20.9.2021 18:03
Avatar
Jaroslav Drobek:26.1.2022 12:42

Při předávání parametru typu char tam, kde se očekává String, je problém, ale při přičítání charu kStringu není problém a jde to i sběžným operátorem +.
Nevyzpytatelná gramatika..

 
Odpovědět
26.1.2022 12:42
Avatar
Jaroslav Drobek:26.1.2022 12:57

syntaxe konverzí i = (int)c; a c = (char)i; působí zvráceně 🙃

 
Odpovědět
26.1.2022 12:57
Avatar
DarkCoder
Člen
Avatar
DarkCoder:26.1.2022 16:17

Nechce se mi věřit, že by v Javě neprobíhala snadná záměna znaku s malým číslem a byly nutné tak zběsilé konverzní postupy jaké jsou uvedeny v odstavci Cézarova šifra. 😀

Odpovědět
26.1.2022 16:17
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Atrament
Člen
Avatar
Odpovídá na DarkCoder
Atrament:26.1.2022 17:11

Samozřejmě, že probíhá, ty konverze jsou tam celkem zbytečné, třeba je tam autor dal z pedagogických důvodů, aby bylo jasné co se tam děje i začátečníkům. Dalo by se to klidně napsat takto bez jediné konverze:

for (char c : slovo.toCharArray()) {
     c += ((c + posun) > 'z') ? - 26 : posun;
     zprava += c;
}

ale to by mohlo začátečníkovi zamotat hlavu :)

 
Odpovědět
26.1.2022 17:11
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Atrament
DarkCoder:27.1.2022 12:09

Ty konverze jsou tam naprosto zbytečné a jejich nasazení do ostrého programu zrovna nevypovídá, že by se jednalo o pedagogický důvod. Tohle se dá přeci vysvětlit jednou větou, že znaky a malá čísla jdou snadno zaměnit a v závislosti na specifikaci formátu určit jaký typ dat se zobrazí. Navíc v článku je zmínka že konverzím se bude věnovat jiný článek a ne to vkládat do článku zaměřujícího se na práci se znaky a řetězci. Toliko ke konverzím, nyní k úryvku kódu.

Ani jeden způsob, zdrojový kód uvedený v článku ani tvá kompaktní forma, není úplně správná. Každá vykazuje odlišné chování chyby. Je třeba brát v potaz posun.

Verze v článku:

i += posun;
// kontrola přetečení
if (i > (int)'z') {
    i -= 26;
}

Co se stane, když hodnota posunu se bude zvyšovat? Hodnota i se bude úměrně zvyšovat, ale korekce odečtu hodnoty 26 tomu nezabrání. To má za následek že se v programu budou vypisovat znaky s vysokým ordinálním číslem a nikoli, že se hodnoty po 'z' vrátí k 'a'. Při malých hodnotách posunu se to chová na první pohled dobře, což vedlo k domněnce, že algoritmus je v pořádku.

Tvá kompaktní verze:

for (char c : slovo.toCharArray()) {
     c += ((c + posun) > 'z') ? - 26 : posun;
     zprava += c;
}

Co se stane, když hodnota posunu se bude zvyšovat? Začne platit podmínka ternárního operátoru v závislosti na vzrůstající hodnotě znaku. Od aktuálního znaku se bude odečítat hodnota 26. To má za následek že se v programu budou vypisovat znaky s menším ordinálním číslem s konstantním posunem -26.

A ještě pár drobností:

K té 26, ač je to hodnota správná, zapsat do programu celočíselný literál v této podobě není správné. Mnohem lepší by bylo deklarovat celočíselnou konstantu bez znaménka, jejíž hodnota by byla 'z' - 'a' + 1.

Hodnotu posunu je dobré normalizovat, v rozsahu o rozsahu ve kterém se chceme pohybovat.

posun %= rozsah;

Nakonec přidávání obsahu na konec řětězce instance třídy String je neskutečně pomalé ač velmi komfortní. Lze vycházet z toho, že původní text a zašifrovaný text budu velikostně 1:1. Lze tedy určit velikost původního pole, alokovat nové pole o stejné velikosti a zapisovat přímo na konkrétní index. Ale to už jsou rychlostní optimalizace, které nejsou předmětem tohoto tématu.

Srdcem celé šifry je tedy následující příkaz:

str2[pos] = (str[pos] + shift > 'z') ? (str[pos] + shift - range) : (str[pos] + shift);

kde:
str - pole s původním textem
str2 - pole se zašifrovaným textem
pos - index pro pozicování v poli
shift - hodnota posunu
range - rozsah malé abecedy ('z' - 'a' + 1)

Tvá podoba zápisu byla takřka správná a rozhodně by se s touto formou měli i začátečníci obeznámit. Vždyť tam není nic složitého (relační operátory, aritmetické operátory, operátory přiřazení, ternární operátor, práce s různými typy proměnných). Naprosté základy, které by začátečníci před prací s řetězci a znaky měli znát. :-)

Odpovědět
27.1.2022 12:09
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Atrament
Člen
Avatar
Odpovídá na DarkCoder
Atrament:29.1.2022 0:10

Ačkoliv máš technicky v mnohém co píšeš pravdu, myslím že ti poněkud uniklo, na jakém levelu se zde pohybujeme a co je účelem těchto článků. V žádném případě zde nejde o vytvoření ultimátně dokonalé verze Cézarovy šifry, ale o procvičení si těch úplně nejzákladnějších jazykových konstrukcí - cyklů, ifů, práce s poli atd. Tohle je osmá lekce kurzu pro naprosté začátečníky - a ti tady mají zatím dost často problém chápat co to vůbec je pole (stačí si projít dotazy pod touto a předchozími lekcemi). Bazírování na detailech jestli to přeteče když tam uživatel zadá 158 místo 3, zde prostě není vůbec na místě, maximálně uvést jako zajímavost v diskusi pod článkem. V naprosté většině těch ukázek v těchto lekcích se přece vůbec nic nekontroluje v zájmu jednoduchosti a přehlednosti. A je to tak správně, protože kdyby se měl vysvětlovat každičký detail a všechno do úplných podrobností, tak jsou ty lekce pětkrát delší a stokrát nezáživnější. Dokonalý způsob jak jednoho od programování odradit už v začátku.

Jenom pro zajímavost - přidávání obsahu na konec řetězce instance třídy String a vůbec například spojování Stringů pomocí + je v Javě 9 a novější optimalizované kompilátorem, takže je to nejenom komfortní ale i rozumně rychlé...

 
Odpovědět
29.1.2022 0:10
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Atrament
DarkCoder:29.1.2022 1:13

Moc dobře vnímám úroveň zdejších uživatelů i kvalitu článků. Každý nějak začínal a já rozhodně nejsem tem co by nováčky jakkoli hanil. Naopak. Procvičení je jedna věc a pochopení a správnost zápisu věc druhá. Obojí je důležité. Smyslem mého pokračování v příspěvku bylo právě to upozornění na chybu v algoritmu. To že jsem k tomu přidal další informace a rady, lze brát jako přidanou hodnotu. Že 99,9% zdrojových kódů zde na fóru neobsahuje ošetření chyb, budíš. Činí to kód jednodušším, s důrazem kladeným na danou látku. Jsou však místa, která je třeba zdůraznit. Právě ta preciznost dělá rozdíl mezi průměrným a špičkovým programátorem. A jsem si jist, že každý chce být dobrý, lepší. Pokud někomu stačí základy, jeho věc..

Možná právě ty základní dotazy v diskuzi souvisí s úplností a správností informací v článcích. Detaily jsou důležité, pak se totiž ukáže, že pocit, že o tom víme vše, je mylný. Do sekce o Javě zavítám sporadicky, ale co se děje v sekci o C, to by jeden žasnul. Nejsmutnější na tom celém je to, že když někdo na chybu upozorní, nikdo ji v článku neopraví. Pak se předávají chybné informace, nováčkům kód nefunguje nebo mu vůbec nerozumí a já se jim ani nedivím, že je to pak odrazuje od pokračování. Náměty na zlepšení už jsem tu nesčetněkrát zmínil.

Co se týká přidávání obsahu na konec instance třídy String, zůstal bych pouze u slov komfortní a rozumně rychlé. Vyhrazení paměti se provádí za běhu, je tam tolik aspektů co činí kód pomalý (rozumějme dostatečně svižný). V příkladu s Cézarovou šifrou a zdrojovým textem, se dá určit velikost pole se zdrojovým textem v době kompilace a tudíž je možné nové pole alokovat staticky. To pole se nemění a nevyžaduje další režii. Zápis lze provádět přímo na konkrétní pozici. Ale máš pravdu, toto jsou pouze optimalizace a ne smysl toho konkrétního článku. Někoho to však může zajímat.. někoho, kdo chce být prostě lepší..

Odpovědět
29.1.2022 1:13
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 115.