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.