Mikä olisi helpoin tapa katsoa merkkijonosta, jokaisen merkin kohdalta, että monesko se merkki on aakkosissa?
esim:
merkkijono = "abcd"; aakkosissa = "1234";
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?
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?
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; }
#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.
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?
Tuostahan näkyy selvästi, että siitä puuttuu yksi << välistä. Korjasin.
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?
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.
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"; } }
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.
>>-operaattori lukee yhden sanan eli seuraavaan tyhjään asti. Rivin saa luettua getline-funktiolla:
getline(cin, merkit);
Tuo
getline(cin, merkit);
ei toimi minulla se vain "hyppää" sen kohdan yli.
... 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);
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.
Aihe on jo aika vanha, joten et voi enää vastata siihen.