Ubuntu Suomen keskustelualueet

Ubuntun käyttö => Ohjelmointi, palvelimet ja muu edistyneempi käyttö => Aiheen aloitti: teele - 07.01.23 - klo:20.30

Otsikko: [ ratkaistu ] c++ stl merkkijono vector-luokan olioksi
Kirjoitti: teele - 07.01.23 - klo:20.30
Haluaisin saada merkkijonon, jossa on välilyönnein  eroteltuja sanoja luetuksi vector-luokan säiliöön.

Toivomus olisi, että homma toimii aika turvallisesti ilman ylivuotoja tai muita ongelmia, vaikka tulevamerkkijono olisi vähän omituisempikin.

Nykyinen versioni on tällainen

Koodia: [Valitse]
  std::vector<std::string> str_to_vec(char* cptr)
  {
    std::vector<std::string> vec;
    std::string tok = "";
         
    while( *cptr != '\0')
    {
      if(*cptr == ' ' && tok != "")
      {
        vec.push_back(trim(tok));  // tok valmis ' '-merkki päätti sen
        tok = "";
        cptr ++;
      }
      else
      {
        tok += *cptr;
        cptr++;
        if( *cptr == '\0')          // tok valmis \n -merkki päätti sen
        {
          vec.push_back(trim(tok));
        }
      }     
    }
    return vec;
  }


Jotta vektoriin ei tule luetuksi välilyöntejä, funktiossa on trim-käsky, joka on toteutettu näin

Koodia: [Valitse]
std::string ltrim(const std::string &s) {
    return std::regex_replace(s, std::regex("^\\s+"), std::string(""));
}
 
std::string rtrim(const std::string &s) {
    return std::regex_replace(s, std::regex("\\s+$"), std::string(""));
}
 
std::string trim(const std::string &s) {
    return ltrim(rtrim(s));
}

Kokonaisuus ei vaikuta kovin tyylikkäältä, kun kyseessä on vain aika yksinkertainen vektoritalletus ja sanojen poiminta.

Olisiko joitain keinoja, miten asian voisi hoitaa varmemmin ja tyylikkäämmin. (esim.nyt kai  ainakin pitäisi varautua siihen, että merkkijonon loppumerkkiä ei koskaan tulisikaa, ja varmaan moneen muuhunkin mahdolliseen ongelmaan)





Otsikko: Vs: c++ stl merkkijono vector-luokan olioksi
Kirjoitti: nm - 08.01.23 - klo:00.45
cplusplus.comissa on varsin hyvä katsaus tähän ongelmaan, kuten jo edellisessä ketjussa (https://forum.ubuntu-fi.org/index.php?topic=57619.0) mainitsin: https://cplusplus.com/faq/sequences/strings/split/

Suosittelen jotain tuolla mainittua menetelmää. Jos haluat erotella sanat kaikilla whitespace-merkeillä ja mahdollisesti ohittaa tyhjät sanat (tai toistuvat välimerkit), sivulla esitetty string::find_first_of() -funktioon perustuva menetelmä on fiksu STL-pohjainen ratkaisu.

Jos sovelluksessa on kuitenkin jo muista syistä riippuvuuksina Boost tai Qt, kannattaa käyttää niiden tarjoamia split-funktioita.
Otsikko: Vs: c++ stl merkkijono vector-luokan olioksi
Kirjoitti: teele - 09.01.23 - klo:20.10
Yritin vielä tällaista tavisversiota

Koodia: [Valitse]
#include <string>
#include<vector>
#include <iostream>

std::vector<std::string> ct_to_st(char *p) //char tokens to string tokens
{
  std::vector<std::string> sv;
  std::string s = "";
 
  while(*p != '\0' ) // mitään ei lisäillä, jos merkkijono on loppu
    {
      while(*p != '\0' && *p == ' ' )
        {
          p++;
        }  // while
      while(*p != '\0' && *p != ' ' )
        {
           s.push_back(*p);
           p++;
        } // while
      sv.push_back(s);
      s = "";
    }  // while 
  return sv;
}

int main(int argc, char **argv )
{
  if(argc != 2)
    {
      std::cout << "ohjelmanimi merkkijono" << std::endl;
      return 1;
    }
  std::vector<std::string> sv = ct_to_st(argv[1]); // eka ohjelmaparametri on merkkijono
  for( auto e : sv)
    {
      std::cout << e << "  " ;
    }
  std::cout << std::endl;
  return 1;
}

Yllättäen kokeilu antoi

Koodia: [Valitse]
$ ./re-koe_03 'xxä     yyy bb  '
xxä  yyy  bb   
$ ./re-koe_03 '  xxä     yyy bb  '
xxä  yyy  bb   
$ ./re-koe_03 'ääåå k m     yyy bb  '
ääåå  k  m  yyy  bb   
$ ./re-koe_03 äää
äää 
$ ./re-koe_03 ' '

$

mistä päättelin, että voisi toimiakin. Pelkkä välilyönti riittää erotinmerkiksi, niin string::find_first_of() -funktion laajempaa valikoimaa ei vielä tarvittane.