Diskuze: Nejspíš nějaké chyby
V předchozím kvízu, Online test znalostí Java, jsme si ověřili nabyté zkušenosti z kurzu.


Matúš Olejník:13.3.2020 20:44
Ahoj, nabudúce sem namiesto obrázka pošli tvoj kód ako text
Správa ktorú chceš zašifrovať je v premennej s = "itnetwork"
Tú si chceš rozsekať zrejme po znakoch čomu naznačuje kód. Avšak
s.split(" ") ti rozseká správu v tomto prípade po medzerách. Keďže však
itnetwork žiadnu medzeru neobsahuje tak v poli znaky bude jeden reťazec,
ktorý bude obsahovať celú pôvodnú správu.
Toto následne spôsobí, že celý cyklus sa vykoná len raz, pretože v tom
poli je len jeden prvok. To som len objasnil prečo práve jeden otáznik
Chcel som písať ďalej, ale ako pozerám viac ten kód tak to máš celkom
zamotané Samozrejme nič v
zlom, treba nejako začať
a
keďže vidím, že sa snažíš tak nebudem písať riešenie ale spýtam sa
ťa aký bol tvoj plán ako by to malo fungovať a môžme to potom dať dokopy
spolu
Napr. čo tam má
riešiť ten otáznik atď
no já zatím tak začínám (a vím, že by to nejspíš šlo jednodušeji,
ale s mýma znalostma to zatím nejde a dokud mi to někdo nevysvětlí nebo se
to někde nedočtu tak jsem spokojen s tímto ) a napadlo mě že když je v
deváté lekci (Základní konstrukce jazyka Java) dekódér morseovky tak že
by jsem mohl zkusit udělat program na zakódování...
String s = "itnetwork";
System.out.printf("Původní zpráva: %s\n", s);
// řetězec s zakódovanou zprávou
String zprava = "";
// vzorová pole
String abecedniZnaky = "abcdefghijklmnopqrstuvwxyz"; //ASCII - 97 až 122
String[] morseovyZnaky = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
"....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...",
"-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
// rozbití řetězce na písmena abecedy
String[] znaky = s.split(" ");
// iterace znaky morzeovky
for (String abecedníZnak : znaky) {
char morseuvZnak = '?';
int index = -1;
for (int i = 0; i < abecedniZnaky.length(); i++) {
if (morseovyZnaky[i].equals(morseuvZnak))
index = i;
}
if (index >= 0) { // znak nalezen
morseuvZnak = morseovyZnaky[-1].charAt(index);
}
zprava += morseuvZnak;
}
System.out.printf("Zakódovaná zpráva: %s\n", zprava);
ten otazník by měl znázorňovat jakože se to neví nebo tak něco a potom to for(int = i, atd...) by ty písmenka mělo najít a zaměnit za morseovku (opět se odkazuji na devátou lekci Základní konstrukce jazyka Java). A k té předešlé odpovědi, měl jsem jenom přidat mezery ke vstupu nebo jsem to špatně pochopil (při přidání mezer se již zobrazil stejný počet otazníků jako písmen ve vstupu, ale morseovka nikde)
Zkus příště třetí pokus a dávej ten kód do tagů (tlačítko nahoře
nad editorem textu </>).
Jinak nebudu teď zasahovat Matúšovi do rad, vysvětluje ti to pěkně, ale mám dojem, že jsi nepochopil, jak funguje pole.
Matúš Olejník:14.3.2020 13:02
Ďakujem, ale kľudne píš som síce zatvorený doma, ale na záhrade je stále čo robiť,
takže nie som toľko pri PC
Matúš Olejník:14.3.2020 13:02
Ahoj, skúsim ti sem dať hint ako dotiahnuť tvoj kód, s tým, že som
niektoré premenné nazval anglicky, čo môžeš urobiť aj ty nech si zvykáš
Ak to stále nepôjde tak píš kľudne ďalej a ja alebo Lubor alebo niekto
iný určite pomôžeme
String unencryptedText = "itnetwork";
//rozseká správu po medzerách, takže pole bude obsahovať jednotlivé slová
String[] unencryptedWords = unencryptedText.split(" ");
//prechádzanie jednotlivých slov, nie písmen!!
for (String unencryptedWord : unencryptedWords) {
//vytvorenie poľa s jednotlivými písmenami daného slova
char[] letters = unencryptedWord.toCharArray();
//prechádzanie jednotlivých písmen
for (char letter : letters) {
//chápem čo si chcel docieliť vo svojom kóde, ale aj keď by mohlo byť lahšie riešenie
//tak môžeš dokončiť svoj nápad :)
//Len treba dávať pozor čo porovnávaš, ty si týmto morseovyZnaky[i].equals(morseuvZnak) porovnával
//String s char a už to by nefungovalo. Rovnako ako som ti ukázal ako prechádzať písmená v slove
//môžeš prechádzať tie tvoje abecedniZnaky keď si ich dáš do poľa znakov abecedniZnaky.toCharArray()
//a budeš pracovať s tým polom
}
}
Keď sa s tým budeš hrať tak si asi všimneš, že napr. morseovyZnaky[-1]
so záporným indexom ti bude hádzať chybu, na ktorú ťa už určite aj
editor upozorňuje tým, že je to podsvietené A rovnako si myslím, že to
dokážeš aj bez toho otazníka
ok
Jak říkal Matúš, je to matoucí text a teď proč...
Uvědom si první věc - ne každý sedí vedle tebe a ne každý přemýšlí
stejně jako ty. Neuvažuješ špatně, ale tvoje pojmenování není
nejvhodnější (proto si ze sebe my ITáci děláme prdel, že z celého objemu
programování jen 5% času vyvíjíme a 95% času vymýšlíme vhodné názvy:)
)
Ale teď vážně. Kupříkladu tvůj popis:
String zprava = "";
Ano, dobře jsi k tomu přidal komentář, ale v tomto případě
zbytečně.
Neboj se psát delší názvy proměnných (klidně i jednoduché malé
věty).
Takže rovnou napiš něco ve smyslu:
String zakodovanaVstupniZpravaProPreklad = "";
Myslím, že u takového pojmenování nikdo nebude čekat, že je to pomocná proměnná či že v tom uvidí výsledek kódu nebo cokoliv jiného.
Teď k tomu poli. Počítač je hloupý stroj (to měj na paměti!. Vždy,
když vrátí nějaký výsledek, tak proto, protože jsi mu to tak řekl).
Ty jsi si uložil 1 String a jedno pole.
Bylo by nejlepší, kdybys rovnou na jednom místě měl pole abecedních znaků
a pole Morseových znaků. Bylo by to přehlednější a minimalizoval bys tím
chybovost.
Nejlepší je i slovo "pole" (v lepším případě field:) ) přidávat i do
názvů polí.
Takže by to mohlo vypadat takhle:
String abecedniZnaky = "abcdefghijklmnopqrstuvwxyz"; //ASCII - 97 až 122
String[] poleAbecednichZnaku = abecedniZnaky.split("");
String[] poleMorseovychZnaku = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
Pak nastává ta tvoje chyba, o které už mluvil Matúš.
metoda split() skutečně rozdělí textový řetěz na pole, ale do uvozovek
zadáváš znak, který má být ten rozdělovač.
Takže když máš třeba slovo bbbabbb a rozdělovač bude "a", tak budeš mít
[bbb] a [bbb].
No a tys řekl počítači:
Rozděl slovo "abcdefghijklmnopqrstuvwxyz" na bloky pomocí mezer.
No a počítač ti řekl: tak fajn, mezera tam není, tak mám jeden blok.
Proto ty jsi pracoval sice se dvěma poli. Jedno pole mělo jedno slovo (a-z) a
druhé pole mělo 26 prvků.
A to už ti Matúš poradil, jak to napravit.
Ten tvůj znak na ten otazník je správné uvažování. Jestli už teď připouštíš možnost, že může nastat varianta, kterou jsi nepředpokládal, tak je to velmi dobrá cesta k tomu, aby ses stal dobrým programátorem.
Teď ti dám radu, jak příštím problémům čelit a jak jsme třeba
postupovali my (já nebo Matúš). Samozřejmě, ber to s nadhledem, my už
nějakou tu dobu programujeme, takže nám se to odehrává v palici, ale
ukážu ti, jak postupovat při tzv. debuggování.
Samozřejmě nejlepší je debugger - to se tu také naučíš, ale třeba teď
můžeš začít se Systémovkou. Nyní už sice tohle až tak moc
nedoporučuju, protože z vlastní zkušenosti musím přiznat, že mě osobně
dlouho trvalo, než jsem přešel plnohodnotně na debugger v IDEčkách,
protože jsem si hodně zvykl na systémovky, ale frameworky to naučí
každého:)
Tvůj kód vracel nesmysl - konkrétně otazník.
Postup uvažování je ptát se. (proč proč proč) a ověřování (funguje to
tady? dostanu se sem? mám se sem dostat? Proč se sem nedostanu)
Neboj se klidně mluvit nahlas. Jednak se naučíš mluvit a hlavně když
budeš mluvit nahlas, tak tím, že to uslyšíš a neřekneš si to jen v
duchu, tak ti to mnohdy i docvakne (on ten mozek asi vážně jinak reaguje na
to, co uslyší, než jen na to, co si myslí:) )
Takže bys mohl postupovat takto:
Proč to vrací otazník a co to má vlastně vracet?
A můžeš si procházet ten kód od main metody. Takže budeš ověřovat:
- vkládám nějaký text do proměnné s. To je sice kravina ověřovat, ale tak v rámci objektivnosti a ať to vypadá drsně, tak si za něj napíšeš na nový řádek:
System.out.println(s);
spustíš kód - fajn, vypíše se to
- to samé se zprávou (je to už hodně zbytečná blbost, ale beru to globálně, že je dobré ověřovat i v budoucnu každý řádek:) )
- abecedníZnaky. Je to string, se kterým budu pracovat. Je v něm uloženo to, co tam má být? Je
- To samé morzeovyZnaky. A vypíšu si to hezky cyklem a ověřím, že je to správné pole i se správným typem)
for(String znak:morseovyZnaky) {
System.out.println(znak);
}
Možná už tady by tě trklo... že by se sem hodilo, abych rovnou ověřil,
že bude i ten předchozí seznam v poli. A třeba bych si s tím pohrál a
ověřil, že je vše na správné cestě, když bych měl dvě pole o stejné
velikosti, tak že bych si vytvořil jen tak z prdele takovou překládací
tabulku.
Takže něco v tomhle smyslu:
String abecedniZnaky = "abcdefghijklmnopqrstuvwxyz"; //ASCII - 97 až 122
String[] poleAbecednichZnaku = abecedniZnaky.split("");
String[] poleMorseovychZnaku = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
for (int i = 0; i < poleAbecednichZnaku.length; i++) {
System.out.printf("%s = %s\n", poleAbecednichZnaku[i], poleMorseovychZnaku[i]);
}
A máš jistotu, že máš dvě připravená pole (a že každý znak bude
správně přirovnaný).
Samozřejmě, až budeš po letech koukat na ten kód, tak zjistíš, že
ještě lepší je třeba na tohle vytvořit si mapu<String, String>, kde
první String bude abecední znak a druhý morseový. No a pak zase zjistíš,
že bude ještě větší sranda načítat to ze souboru či databáze:) Ale to
jen poznámka k motivaci:)
No a takhle bys došel na to, že ti třeba ten tvůj split(" ") nevrací to, co by sis přál. Protože místo hezkého seznamu prvků ti to vrátí:
abcdefghijklmnopqrstuvwxyz = .-
A to je divné, že?
No a to samé, když budeme pokračovat dál
Takže 5) by sis opět cyklem ověřil, že String[] znaky = s.split(" "); ti
vrátí pole znaků (v tomhle případě bys očekával výstup:
i
t
n
e
t
w
o
r
k
No a ty dostaneš
itnetwork
Což by mohlo být i matoucí, protože by sis myslel, že na jednom řádku je
to v pořádku. Proto je dobré si to pole projít a ke každému znaku i něco
přidat. Příklad:
String[] znaky = s.split(" ");
for (int i = 0; i < znaky.length; i++) {
System.out.println(i + ": " + znaky[i]);
}
A tady bys zjistil, že je něco divného, protože bys očekával už určitě 9 řádků a ono ti to vrátí jen jeden. A to už je hodně zvláštní.
- klidně i v tom průchodu, kdy procházíš jednotlivé znaky (neboli to, cos udělal v bodě pět), tak hned pod hlavičku cyklu si pro kontrolu ty znaky vypiš. V podstatě bys tím provedl kontrolu, co byla v bodě pět
- Ten char morseuvZnak = '?'; bych určitě necpal do cyklu. Zbytečně takhle vytváříš a zahazuješ proměnné. Ono se to nezdá, ale každé vytváření proměnné znamená několik operací (vytvoř místo v paměti pro proměnnou, proměnné přiřaď znak, proměnnou ulož a na konci interace tuto proměnou zahoď a v další interaci vytvoř novou proměnnou... atd. atd. Pochybuju, že bys to dělal jako člověk, tak proč k tomu nutíš počítač?:) )
Takže tohle bych určitě přesunul třeba na začátek metody, pokud ji
budeš využívat jen tady.
Není to podstatná chyba, ale nauč se takhle uvažovat;)
Jinak zase pojmenování - morseuvZnak... Ano, v takovém lehkém kódu je to
tolerovatelné, ale teď si představ, že pracuješ kupříkladu v jiné
třídě a teď dostaneš tohle:
MorseovaAbeceda morseovaAbeceda = new MorseovaAbeceda();
morseovaAbeceda.znak();
No a jaký znak to asi vrátí? Vůbec to není intuitivní.
Jo kdyby tam bylo něco v tomhle smyslu:
MorseovaAbeceda morseovaAbeceda = new MorseovaAbeceda();
morseovaAbeceda.getOznaceniNeznamehoZnaku();
(get se budeš učit později, když se budeš učit metody)
Tak už můžu tušit, že tato metoda vrátí něco (podle datového typu,
jestli číslo nebo String nebo char, prostě něco), čím označuje znak,
který nezná. To už je jiné kafe.
Proto bych to takhle nějak nazval i u tebe, třeba právě tím
označeníNeznamehoZnaku. Právě tímto jsi nachytal Matúše, mě a
kohokoliv jiného, protože nebylo patrné, co ten otazník znamená. Jestli to
měl být tvůj nový vymyšlený znak, nebo právě takové označení,
atd.
Neboj se proměnné popisovat delšími názvy. Furt lepší je názvy
zkracovat, než po druhém luštit, co vlastně ta proměnná má znamenat.
- zase - index... Ok, toto označení se používá, ale v samostatných metodách, kde je patrné, že se skutečně pracuje se specifickým indexem a označuje to nějakou hodnotu potřebnou pro výpočet nebo iteraci nějakého průběhu. Tady procházíš znaky foreachem a najednou narazím na nějaký index. Nevím, jestli je to index pole, index znaku index počtu králíků, které má soused v kotcích. Takže pojmenovávat to lépe.
- No a tady těmi systémovky a otázky bys přišel i na to, že tam máš chybu právě kvůli tomu tvému morseovuZnaku. Blbé pojmenování a tak ti to ani hned tak nedojde, ale ty se v podstatě ptáš neustále, dokola, jestli je v tom vloženém znaku otazník. No a samozřejmě, že ti to nevrátí žádný index, protože není a i kdyby byl, tak ti to žádný index nevrátí, protože ho nemáš v těch tabulkách.
Navíc stačil by ti jeden for a index máš přehledně v něm:)
Tady ti to posílám funkčně, tak si to porovnej
String vstupniZpravaProPreklad = "test";
String zakodovanaVystupniZpravaProPreklad = "";
char oznaceniNeznamehoZnaku = '?';
String abecedniZnaky = "abcdefghijklmnopqrstuvwxyz"; //ASCII - 97 až 122
String[] poleAbecednichZnaku = abecedniZnaky.split("");
String[] poleMorseovychZnaku = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....",
"..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-",
"...-", ".--", "-..-", "-.--", "--.."};
//Následující podmínka je jenom taková kontrola proti tomu, když bys nevyplnil nic:)
if (vstupniZpravaProPreklad != null && !vstupniZpravaProPreklad.equals("")) {
for (String znakVlozenehoSlova : vstupniZpravaProPreklad.split("")) {
for (int i = 0; i < poleAbecednichZnaku.length; i++) {
//následující podmínku by sis mohl vyložit slovy: Pokud najdu znak, tak ho přidám do
// výstupní textu a ukončím smyčku (slovem break)
if (poleAbecednichZnaku[i].equals(znakVlozenehoSlova)) {
zakodovanaVystupniZpravaProPreklad += poleMorseovychZnaku[i];
break;
}
//do následující podmínky se dostaneš pouze za předpokladu, že jsi nenašel znak v poli.
// Tato podmínka platí pouze pro poslední průchod. Kdyby se v posledním průchodu ještě
// vyskytoval požadovaný znak, tak se zapíše a smyčka se ukončí (pomocí break).
// Takže tato podmínka skutečně projde pouze v jednom případě. Když se jedná o poslední znak z pole
// abecedy (čili "z") a pokud ani ten neprojde.
if (i == poleAbecednichZnaku.length - 1) {
zakodovanaVystupniZpravaProPreklad += oznaceniNeznamehoZnaku;
}
}
zakodovanaVystupniZpravaProPreklad += " | ";
}
}
System.out.printf("Původní zpráva: %s\n", vstupniZpravaProPreklad);
System.out.printf("Zakódovaná zpráva: %s\n", zakodovanaVystupniZpravaProPreklad);
Ach jo... proč mě vždycky z malé rady vyjde slohová práce?-.-
Matěj Klimeš:14.3.2020 18:29
To možná moc ne, myslel jsem si, že to pochopím za běhu, ale jak vidíš
Díky moc, asi nějak takhle jsem to potřeboval vysvětlit. Je mi 15 a teprve letos půjdu ne střední školu, obor IT. Myslím si, že po tomhle skvělém podrobném vysvětlení jsem to pochopil.
Matúš Olejník:14.3.2020 22:08
Myslím, že to sme všetci očakávali po tej krátkej správe "ok"
Zobrazeno 12 zpráv z 12.