Terve! Olen uusi käyttäjä täällä ohjelmointiputkassa ja ongelmani on seuraavanlainen. Pitäisi c++ kielellä saada aikaiseksi ohjelma, joka kääntää morse koodina annetun syötteen tekstiksi. Koodi annetaan siten että merkkien välissä on välilyönti esim. "... --- ..." = "sos". Tässä on mitä olen saanut aikaiseksi. Ja näin etukäteen. tiedän, koodi on erittäin rumaa ja sen saisi tehtyä todella paljon lyhyemmin, mutta en juuri muuten sitä osaisi tehdä.(vielä :D) (juuri aloittanut c++:an parissa). Lyhensin koodin keskiosan, koska muuten se olisi tajuttoman pitkä. väärän syötteen saadessaan ohjelman pitäisi merkin tilalle tulostaa [error] (ei ole koodissa vielä). Laitoin tämän tänne siksi etten itse huomaa virhettä, joten vinkit ovat tervetulleita. kiitos jo etukäteen :)
#include <cstdlib> #include <iostream> #include <string> using namespace std; int main(int argc, char *argv[]) { int j; int i; string apu; string morse; cout << "Morse Translator" << endl; getline (cin, morse); for (j=0; j<=morse.length(); j++) { for (i = 0; morse[i] != ' '; i++) { apu += morse[i]; } if (apu == ".-") { cout << "a"; } else if (apu == "-...") { cout << "b"; } . . . else if (apu == "--..") { cout << "z"; } } system("PAUSE"); return EXIT_SUCCESS; }
Paljon siistimmän tuosta koodista ainakin saisi, jos taulukoisi nuo mahdolliset merkit ja niitä vastaavat morsenaakkoset.
char[] aakkoset = {'a', 'b', ..., 'z'}; string[] morset = {".-", "-...", ..., "--.."};
Tai ehkä vielä parempi, jos tekisi kuvauksen (map) joukosta A (merkistö) joukkoon B (morsenaakkoset) vähän tähän tyyliin:
morset = { 'a' -> ".-", 'b' -> "-...", ..., 'z' -> "--..", }
Tosin enpä tosin itsekään osaisi tehdä tuota C++:lla ainakaan suoralta kädeltä.
Sitten siihen varsinaiseen ongelmaan (jota et tosin esittänyt ollenkaan tai sitten olen sokea :)), mutta veikkaisin kuitenkin, että ongelmasi on se, että apu-muuttujaa ei alusteta missään vaiheessa eikä myöskään nollata merkkien tulkkaamisen välissä ja toinen ongelma lienee tuolla rivillä:
for (i = 0; morse[i] != ' '; i++)
Eli se ei riipu j:stä ollenkaan (toisin sanoen luet aina vain ensimmäisen merkin).
Tässä yksi esimerkkiratkaisu:
#include <iostream> #include <sstream> #include <string> using namespace std; // Morse-tietotyyppi struct Morse { // Viivoista ja pisteistä koostuva merkkijono... string mors; // ..ja sitä vastaava kirjain. char merk; }; // Merkit vakiotaulukkoon const int MERKKIEN_MAARA = 3; const Morse merkit[MERKKIEN_MAARA] = { { ".-", 'a' }, // .... { "...", 's' }, { "---", 'o' } }; // Funktio joka muuttaa morsejonon kirjaimeksi char morseToChar(string morse) { // Käydään merkkitaulukko läpi for (int i = 0; i < MERKKIEN_MAARA ; ++i) { // Katsotaan täsmääkö if (morse == merkit[i].mors) { // Palautetaan vastaava merkki return merkit[i].merk; } } // Tuntematon merkki, palautetaan ! return '!'; } int main() { string tekst; cout << "Morse converter\nAnna morsemerkit:"; getline(cin, tekst); // Tehdään luetusta syötteestä merkkijonovirta istringstream is(tekst); string apu; // Luetaan virrasta sana kerrallaan while (is >> apu) { // Tehdään muunnos cout << morseToChar(apu); } cout << endl; return 0; }
Näyttää siltä että apu ei koskaan tyhjene. Jatkat seuraavasta merkistä vaikka sisällä on jo käyty pidemmälle. Sisempi for näyttää aina aloittavan nollasta uudelleen.
Kiitos vastauksista! :) Niin tosiaan olisin voinut selvemmin ilmaista :D Nyt koodi näyttää tältä. Sanoit sami ettei i riipu mitenkään j:stä? Miten saisin sen ilmaistua koodissa? (tyhmä minä :D) edelleenkään ei ohjelma tulosta mitään/tulostaa väärin. *huoh* Missähän se vika...
#include <cstdlib> #include <iostream> #include <string> using namespace std; int main(int argc, char *argv[]) { int j; int i; string apu; string morse; cout << "Morse Translator" << endl; getline (cin, morse); apu = ""; // Alustetaan muuttuja apu for (j = 0; j<=morse.length(); j++) { for (i = 0; morse[i] != ' '; i++) { apu += morse[i]; } if (apu == ".-") { cout << "a"; } else if (apu == "-...") { cout << "b"; } . . . else if (apu == "--..") { cout << "z"; } apu = ""; //Alustetaan muuttuja merkkien tulkinnan välissä } system("PAUSE"); return EXIT_SUCCESS; }
EDIT: Ei kun tietenkin apuun pitää lisätä ne merkit. Tämä on virheellistä tietoa!!!! Poistin ja korjaan. Nyt se on varmaan jotain semmoista mitä pitää.
EDIT2: Tosin taitaa viimeinen merkki jäädä tulostamatta.
Stringejähän ei periaatteessa tarvitse alustaa, koska oletusrakentaja alustaa ne tyhjäksi.
for (j = 0; j<=morse.length(); j++) { // Jos tulee tyhjä merkki, tulostetaan ensimmäinen kirjain if (morse[j] == ' ') { if (apu == ".-") { cout << "a"; } else if (apu == "-...") { cout << "b"; } . . . else if (apu == "--..") { cout << "z"; } // Tyhjätään apu apu = ""; // Hypätään seuraavaan merkkiin continue; } apu += morse[j]; }
Iffittelyn voisi toki vaihtaa switch-case -rakenteeksi.
Kiitos korjauksesta! Viimeinen merkki tosiaan jää tulostamatta. Millähän sen saisi tulostamaan myös viimeisen merkin? :S
Muuta tämä rivi:
// if (morse[j] == ' ') if (j == morse.length() || morse[j] == ' ')
Yksi vaihtoehto voisi olla noiden merkkien rekisteröimiseen std::map.
#include <map> std::map<std::string, char> mMorseMap; mMorseMap[".-"] = 'a'; mMorseMap["-..."] = 'b'; . . mMorseMap["--.."] = 'z'; char getChar(const std::string& morse) { std::map<std::string, char>::iterator i = mMorseMap.find( morse ); if( i != mMorseMap.end() ) return *i; return '!'; // VIRHE, MERKKIÄ EI OLE }
Tiiviimmin tuon saisi tehtyä replace-toiminnolla, vaikka koodista ei aivan optimaalista tulekaan (tai ainakaan tästä purkkaratkaisusta ei tullut).
#include <string> #include <iostream> using namespace std; struct morse_t { string koodi; char merkki; } morse[] = { {"...", 's'}, {"---", 'o'} }; #define MORSEJA (sizeof(morse) / sizeof(morse[0])) void muuta(string &teksti) { int i; string::size_type pos; // Väli alkuun ja loppuun, jotta toimii oikein teksti = ' ' + teksti + ' '; for (i = 0; i < MORSEJA; ++i) { char c = morse[i].merkki; string s = ' ' + morse[i].koodi + ' '; // Niin kauan kuin löytyy morsekoodi, korvataan se merkillä while ((pos = teksti.find(s)) != string::npos) { teksti.replace(pos + 1, s.length() - 2, 1, c); } } // Korvataan vielä ylimääräiset välilyönnit pois while ((pos = teksti.find_first_of(' ')) != string::npos) { teksti.replace(pos, 1, ""); } } int main(void) { string txt = "... --- ..."; cout << txt << endl; muuta(txt); cout << txt << endl; return 0; }
Ihan sivuhuomautuksena vaan, eikös morsekoodit menne oikeasti ihan ilmankin välilyöntejä tähän tapaan ...---.....-.--...-... Tällä periaatteella koodi menisi vähän toisin. Mutta voihan sitä koodailua harjoitella noinkin...
Äh, http://fi.wikipedia.org/wiki/Sähkötys
O ---
S ...
: ---...
Eipä tuosta taitaisi millään tietää ilman taukoa mitä tarkoitetaan.
[muokattu]
Lisäänpä vielä yhden vaihtoehtoisen menetelmän. Puurakenteen innoittamana huomasin wikipediasta tämmöisen: http://en.wikipedia.org/wiki/Morse_code#Alternative_display_of_more_common_characters_for_the_international_code
Joten sovelsin siitä seuraavan koodin, käyttäen puun esittämiseen taulukkoa.
#include <iostream> #include <string> int main(void) { // kaikkia erikoismerkkejä ei löydy, ainoastaan ne jotka sain // helposti houkuteltua näppäimistöltä ulos muut on korvattu // välilyönneillä std::string codes = " ETIANMSURWDKGOHVFULÄPJBXCYZQÖ 54 3É 2 È+ À 16=/ 7 Ñ8 90 ?_ \" . @ ' - ;! , : "; std::string morse = ".... . .-.. .-.. --- .-- --- .-. .-.. -.."; std::string message; std::string::size_type pos; std::string::iterator iter; pos = 0; for (iter = morse.begin(); iter != morse.end(); iter++) { switch (*iter) { case '.': pos = 2*pos+1; break; case '-': pos = 2*pos+2; break; default: message += codes.at(pos); pos = 0; break; } } // lisätään vielä viimeinen merkki jos koodin jälkeen ei tule tyhjää if (pos != 0) { message += codes.at(pos); } std::cout<<morse<<std::endl; std::cout<<message<<std::endl; return 0; }
"Tehokkuus" leinee O(n log n), koodi ei ole kaikkein parhainta mutta periaate selvinnee tuostakin.
Aihe on jo aika vanha, joten et voi enää vastata siihen.