Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Merkkijonovertailua

Sivun loppuun

Cc [10.07.2006 00:10:48]

#

Mikä olisi helpoin tapa katsoa merkkijonosta, jokaisen merkin kohdalta, että monesko se merkki on aakkosissa?
esim:

merkkijono = "abcd";
aakkosissa = "1234";

T.M. [10.07.2006 00:47:12]

#

Merkin "a" ascii arvo on 97, merkin "z" 122.

Noilla tiedoilla pitäisi kyetä tekemään yksinkertainen laskutoimenpide jolla saat haluamasi luvut.

Ascii arvon tais saada jotenkin näin:

(int)merkkijono[0]

Jos C-kielestä puhuttiin?

Cc [10.07.2006 01:31:46]

#

yritän itse tehdä tarkistusta tällä tavalla

for(int i=0; i<merkkijono.length(); i++) {
   for(int a=0;a<29; a++) {
      if(merkkijono[i] == aakkoset[a]) {
         std::cout << "täsmää " << a << std::endl;
      }
   }
}

minulla on 29 pitkä taulukko missä on kaikki suomenkielen aakkoset, sen nimi on aakkoset.

Tämä koodi huutaa tuossa if-kohdassa tällä tavoin.

no match for 'operator==' in 'aakkoset[a] == (&merkkijono)->std::basic_string<_CharT, _Traits, _Alloc>::operator[] [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>](((unsigned int)i))'

missä on vika? itse en sitä huomaa?

Sisuaski [10.07.2006 03:31:59]

#

Asia menee kätevimmin suunnilleen niin, kuin T.M. sanoikin, eli vertaat vain nykyisen kirjaimen ja aakkosten alun eroa, paitsi että sinun ei tarvitse tietää 'a'-kirjaimen ascii-arvoa, vaan voit kirjoittaa koodiin vain 'a'. Tuo sinun esimerkkikoodisi menisi tällä tyylillä suunnilleen näin:

for(int i=0; i<merkkijono.lenght(); i++) {
  std::cout << "täsmää " << int(merkkijono[i]-'a')+1 << std::endl;
}

Metabolix [10.07.2006 08:04:15]

#

#include <ctype.h>

for (i = 0; i < merkkijono.length(); ++i) {
  // Onko se a-z tai A-Z?
  if (isalpha(merkkijono[i])) {
    cout << (i+1) << ". merkki kuuluu aakkosiin, se on " << merkkijono[i] << endl;
  }
  // Onko se numero?
  else if (isdigit(merkkijono[i])) {
    cout << (i+1) << ". merkki on numero " << merkkijono[i] << endl;
  }
  // Ei ole
  else {
    cout << (i+1) << ". merkki on " << merkkijono[i] << endl;
  }
}

Skandeja tuossa ei ole, mutta asian voi korjata korvaamalla isalpha-funktion tällaisella:

int oma_isalpha(int ch)
{
  const char *omat_merkit = "åäöÅÄÖ";
  int i;

  // Jos se on muutenkin aakkonen
  if (isalpha(ch)) {
    return isalpha(ch);
  }
  // Muuten käydään omien merkkien taulukko läpi
  for (i = 0; omat_merkit[i]; ++i) {
    if (omat_merkit[i] == ch) {
      return 1;
    }
  }
  // Ei löytynyt, palautetaan nolla
  return 0;
}

Jos haluaa standardikirjastosta tuossakin luopua, voi toki naputella omiin merkkeihin kaikki haluamansa merkit ja jättää alusta isalpha-tarkistuksen pois.

Cc [10.07.2006 10:22:39]

#

Sisuaski jos oikein ymmärsin tuon sinun tavan niin joutuisin jokaiselle aakkoselle kirjoittamaan oman tarkistuksen?

Metabolix tuo sinun koodisi huutaa

    cout << (i+1) ". merkki kuuluu aakkosiin, se on " << merkkijono[i] << endl;

rivistä. se sanoo että haluaa ; merkin mutten tajua mihin se sitä tarvitsee?

Metabolix [10.07.2006 10:52:10]

#

Tuostahan näkyy selvästi, että siitä puuttuu yksi << välistä. Korjasin.

koo [10.07.2006 11:31:31]

#

Tuo vertailumerkkijonon käyttö on parempi idea kuin räknätä merkkien ascii-koodeilla. Tällä tapaa kun järjestyksen saa just haluamakseen eikä tarvitse kauheasti miettiä, mitkä ovat ääkkösiä tai vaikka kontrollimerkkejä ja mitkä niitä amerikkalaisillekin kelpaavia kirjaimia.

Tällaista juttua on oikeastaan mahdoton saada pelaamaan oikein kaikilla merkistöillä ja kaikilla kieliasetuksilla. C-kirjaston strcoll voisi auttaa tai sitten ei.

Tuo Ccn aiempi for-luuppi on sinänsä ihan ok (vaikka meikäläinen kyllä suosisi tällaisissa enempi standardiluokkien omia find- ja locate-juttuja). Virhe aiheutuu jostakin, joka on koodipätkän ulkopuolella. Onkos tuossa näytillä justiinsakin se koodi, josta kääntäjä valittaa, ja millaisia olivatkaan merkkijonon ja aakkosten määrittelyt ihan oikeesti?

Cc [10.07.2006 12:20:41]

#

koo: Tuo on justiinsa se kodi josta se kääntäjä valitaa..

std::string merkkijono, aakkoset[29] = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "å", "ä", "ö"};

Tuossa ovat määrittelyt merkkijonolle ja aakkosille.

Metabolix [10.07.2006 12:25:09]

#

No ethän sinä nyt ole yhtä merkkiä vertaamassa kokonaiseen stringiin.

std::string aakkoset = "abcdefg";
std::string::size_type paikka;
for (i = 0; i < merkit.length(); ++i) {
  paikka = aakkoset.find_first_of(merkit[i]);
  if (paikka == std::string::npos) {
    cout << "Ei ole.\n";
  }
  else {
    cout << "On, aakkosten " << (paikka+1) << ". merkki\n";
  }
}

Cc [10.07.2006 12:44:29]

#

Kiitos Metabolix sinulle, tuo auttoi minua oikeille raiteille :)

EDIT: Huomasin vielä pienen ongelman, jos merkkijono sisältää välilyönnin niin se tulostus pysähtyy siihen, miten saisin sen korjattua.

Metabolix [10.07.2006 14:36:17]

#

>>-operaattori lukee yhden sanan eli seuraavaan tyhjään asti. Rivin saa luettua getline-funktiolla:

getline(cin, merkit);

Cc [10.07.2006 14:59:45]

#

Tuo

getline(cin, merkit);

ei toimi minulla se vain "hyppää" sen kohdan yli.

Metabolix [10.07.2006 15:39:08]

#

... koska puskurissa on rivinvaihto jäljellä edellisen lukemisen jäljiltä. Ne pitää ensin ottaa pois sieltä lukemalla ws:ään, joka on sellainen kontrolliolio, joka poistaa tyhjät puskurista.

getline(cin >> ws, merkit);

Sisuaski [18.07.2006 17:02:59]

#

Cc kirjoitti:

Sisuaski jos oikein ymmärsin tuon sinun tavan niin joutuisin jokaiselle aakkoselle kirjoittamaan oman tarkistuksen?

Et joutuisi, tuo esimerkkini perustuu siihen, että suunnilleen jokaisessa merkistössä on aakkoset määritelty peräkkäisiksi merkeiksi, joten esimerkiksi 'c'-'a' palauttaa 2, koska c:n ja a:n erotus on aakkosissakin 2. Funktiona menisi näin:

short monesko(char ch)
{
  if (isupper(ch))
    return ch-'A'+1;
  if (islower(ch))
    return ch-'a'+1;
  throw(std::logic_error("Merkki ei ole kirjain!"));
}

Mutta tosiaan jos tarkoitus on vain tarkistaa, kuuluuko merkki aakkosiin, on metabolixin esittelemä tapa selkeästi parempi ratkaisu kuin ruveta itse tarkastelemaan monesko merkki se on.


Sivun alkuun

Vastaus

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

Tietoa sivustosta