Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Morse-koodin kääntäjä (C++)

Sivun loppuun

Blkout [31.10.2007 20:38:55]

#

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;

}

Sami [31.10.2007 21:06:48]

#

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).

TsaTsaTsaa [31.10.2007 21:07:44]

#

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;
}

Niko [31.10.2007 21:10:38]

#

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.

Blkout [31.10.2007 22:00:53]

#

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;
}

TsaTsaTsaa [31.10.2007 22:42:43]

#

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.

Blkout [01.11.2007 16:01:59]

#

Kiitos korjauksesta! Viimeinen merkki tosiaan jää tulostamatta. Millähän sen saisi tulostamaan myös viimeisen merkin? :S

Metabolix [01.11.2007 16:21:14]

#

Muuta tämä rivi:

// if (morse[j] == ' ')
if (j == morse.length() || morse[j] == ' ')

Mazzimo [02.11.2007 11:39:44]

#

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
}

Metabolix [02.11.2007 13:00:18]

#

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;
}

User137 [02.11.2007 16:08:20]

#

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]

zacura [02.11.2007 21:44:20]

#

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_f­or_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.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta