Program do wypisywania inicjałów ze stringa

0

Witam,
Tworze program wypisujący inicjały słów ze stringa np. "Patryk Robert" --> PR , "Tomek przemek" --> Tp
Program w zasadzie działa prawidłowo, jest tylko jedna kwestia.
Na początku miałem problem tego typu, że przy pustym inpucie na wyjściu miałem znak \0. Dodałem więc warunek na początku funkcji name.empty(), return "";.
Później doszedłem jeszcze do sytuacji, że gdy mój string kończy się na spację np. "Patryk Patryk " to moim wynikiem jest PP\0 czyli znów pojawia się \0.
Moje pytanie brzmi jak mogę zmodyfikować ten kod aby program nie wypisywał \0 w tej sytuacji.

Dodam, że dla utrudnienia mogę użyć tylko tych trzech bibliotek jakich użyłem poniżej

#include<iostream>
#include<cctype>
#include<string>

std::string initials(const std::string &name)
{
    if(name.empty())
    {
        return "";
    }
    std::string init;
    int i = 1;

    if(!isspace(name[0]))//pierwszy znak to litera
    {
        init += name[0];//pierwsza litera stringa to pierwsza litera inicjalu
        for(char prev = name[i], next = name[i+1]; i < name.size(); i++)
        {
            if(isspace(name[i]) && !isspace(name[i+1])) //" [litera]"
            {
                init += name[i+1];
            }

        }
        for(int p = 0; p < init.size(); p++)
        {
            if(init[p] == '\0')
            {
                std::cout << "error ";
            }
        }

        return init;
    }
    else //pierwszy znak nie jest litera
    {
        i = 0;
        for(char prev = name[i], next = name[i+1]; i < name.size(); i++)
        {
            if(isspace(name[i]) && !isspace(name[i+1])) //" [litera]"
            {
                init += name[i+1];
            }

        }
        for(int p = 0; p < init.size(); p++)
        {
            if(init[p] == '\0')
            {
                std::cout << "error ";
            }
        }

        return init;
    }
}

int main()
{
    std::cout << initials("Patryk Patryk  ") << std::endl;
}
1

Moje pytanie brzmi jak mogę zmodyfikować ten kod aby program nie wypisywał \0 w tej sytuacji.

Napisać go od nowa, żadnego trima tam nie potrzebujesz. Z Twojego opisu wnioskuję, że z wyjątkiem pierwszego znaku, szukasz par spacja+litera. Rozwiązanie można zmieścić w jeszcze mniejszej ilości linijek, ale tak jest w miarę czytelnie.

std::string initials(const std::string &name)
{
    std::string ret;
    auto it = name.begin();
    auto next = std::next(it);
    if(isalpha(*it))
    {
      ret += *it;
      it = next;
      next = std::next(next);
    }
    for(;it != name.end() && next != name.end(); it = std::next(it), next = std::next(it))
    {
      if(isspace(*it) && isalpha(*next))
      {
        ret += *next;
        it = next;
      }

    }

    return ret;
}
0

Brzmi jak idealne zadanie dla stringstreama. Widzę, że możesz używać biblioteki standardowej, więc zainkluduj tylko <sstream> i właściwie gotowe.

4
std::string initials(const std::string &name) {
    std::string output;
    bool prev_is_space = true;
    for (char c : name) {
        if (prev_is_space && isalpha(c))
            output += c;
        prev_is_space = isspace(c);
    }
    return output;
}

wszyscy tam komplikujecie

0

Proponuję aby każdy z forum dodał swoją wersję xd

std::string initials(const std::string& name)
{
  std::string inits = "";
  inits += name[0];

  for(auto it = name.begin(); it != name.end(); ++it){
    if(*it == ' '){
      inits += *(it + 1);
      break;
    }    
  }
  return inits;
}
0

@enedil: Nice, ja raczej strzelałem, żeby find użyć, ale nie udało mi się krócej niż 10 wierszy.

std::string initials(const std::string &name) {
    std::string inits = isalpha(name[0]) ? std::string(1, name[0]) : std::string{};
    auto pos = name.find(' ') + 1;
    while(pos < name.size()){
        if(isalpha(name[pos]))
           inits += name[pos];
        pos = name.find(' ', pos) + 1;
    }
    return inits;
}
2

C++20 i biblioteka std::ranges

#include <iostream>
#include <ranges>

using namespace std;

int main()
{
    string name {"  John   Rambo     Junior "};

    auto initials = [prev_is_space=true]( auto c ) mutable {
        bool result {isalpha(c) && prev_is_space};
        prev_is_space = isspace(c);
        return result;
      };

    for( auto c : name | views::filter(initials) ) cout << c;
}

https://godbolt.org/z/d86ajaeWW

5

Skróciłbym ten kod do

int main()
{
    string name {"  John   Rambo     Junior "};

    auto initials = [prev_is_space=true]( auto c ) mutable {
        return exchange(prev_is_space, isspace(c)) && isalpha(c);
    };

    for( auto c : name | views::filter(initials) ) cout << c;
}

Albo mój oryginalny pomysł:

int main()
{
    stringstream names {"  John   Rambo     Junior "};
    for (string name; names >> name;)
        cout << name.front();
}
2

Ja wolę dać to (same testy catch2): https://godbolt.org/z/jof49M89Y https://godbolt.org/z/KbE3e84r9

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0