Farzan_alm
Farzan_alm

Reputation: 25

converting string to sentence case in c++

I wrote this code for converting string to sentence case but i don't know where is the problem

for (int i = 0; s[i] != '\0'; i++)
{
    if (i == 0 && s[i] >= 'a' && s[i] <= 'z')
    {
        s[i] -= 32;
        cout << s[i];
    }
    else if (s[i] == '.')
    {
        if (s[i+1] == ' ')
        {
            if (s[i + 2] >= 'a' && s[i + 2] <= 'z')
            {
                s[i + 2] -= 32;
                cout << s[i + 2];
            }
        }
        else
        {
            if (s[i + 1] >= 'a' && s[i] <= 'z')
            {
                s[i + 1] -= 32;
                cout << s[i + 1];
            }
        }
    }
    cout << s[i];
}

the problem is for example if i give the

video provides a powerful way to help you prove your point. when you click online video, you can paste in the embed code for the video you want to add. you can also type a keyword to search online for the video that best fits your document. to make your document look professionally produced, word provides header, footer, cover page, and text box designs that complement each other. for example, you can add a matching cover page, header, and sidebar.

the output is like this

VVideo provides a powerful way to help you prove your pointW. When you click online video, you can paste in the embed code for the video you want to addY. You can also type a keyword to search online for the video that best fits your documentT. To make your document look professionally produced, word provides header, footer, cover page, and text box designs that complement each otherF. For example, you can add a matching cover page, header, and sidebar.video provides a powerful way to help you prove your point. when you click online video, you can paste in the embed code for the video you want to add. you can also type a keyword to search online for the video that best fits your document. to make your document look professionally produced, word provides header, footer, cover page, and text box designs that complement each other. for example, you can add a matching cover page, header, and sidebar.

so basically one time it print the first letter of each sentence before dot and then upper case the first letter of sentence and after that repeats the input

Upvotes: 0

Views: 1202

Answers (3)

Vasilij
Vasilij

Reputation: 1941

Here is another solution, I think it is more readable. It also uses a lambda with capture and STL algorithm.

#include <string>
#include <algorithm>

// returning function
std::string make_sentence(std::string const &str) {
    std::string ans;
    ans.reserve(str.size()); // we already know the size of the answer - optomization to allocate only once

    bool search{true}; // our state variable - initially true
    // we use std::back_inserter to populate our answer string
    std::transform(std::begin(str), std::end(str), std::back_inserter(ans), 
    [search] (auto &s) mutable // note the mutable here, by default captured search is const
    {
        // s is a char
        if (s == ' ') return s;
        if (s == '.') {
            search = true; // change state to true after dot
            return s;
        }
        
        if (search) { 
        // if we were searching for the start of a sentence
            search = false; // stop search
            
            // use either of this return statements, but in real-life beware encodings. String manipulation is pain.
            return std::toupper(s, std::locale()); 
            //return static_cast<char>(std::toupper(s));
        }
        return s;
    });
    return ans;
}

// modifying function
void make_sentence2(std::string &str) {

    bool search{true}; // our state variable - initially true
    // we use the same iterator std::begin(str) to modify the same string - it is safe to do so since we do not invalidate iterators
    std::transform(std::begin(str), std::end(str), std::begin(str),
    [search] (auto &s) mutable // note the mutable here, by default captured search is const
    {
        // s is a char
        if (s == ' ') return s;
        if (s == '.') {
            search = true; // change state to true after dot
            return s;
        }

        if (search) {
        // if we were searching for the start of a sentence
            search = false; // stop search    
            
            return std::toupper(s, std::locale());
        }
        return s;
    });
}

int main() {
    const std::string str = "video provides a powerful way to help you prove your point. when you click online video, you can paste in the embed code for the video you want to add. you can also type a keyword to search online for the video that best fits your document. to make your document look professionally produced, word provides header, footer, cover page, and text box designs that complement each other. for example, you can add a matching cover page, header, and sidebar.";
    
    auto str2{str}
    auto ans = make_sentence(str);
    make_sentence2(str2);

    std::cout << ans << '\n;
    std::cout << str2 << '\n';

    return 0;
}

Upvotes: 1

vishwampandya
vishwampandya

Reputation: 1187

Just comment out or remove two lines(becuase they are generating that extra character) and the code will work as you want :

  1. cout << s[i + 2]; and

  2. cout << s[i + 1];

Here's is the example for the same :

  for (int i = 0; s[i] != '\0'; i++)
{
    if (i == 0 && s[i] >= 'a' && s[i] <= 'z')
    {
        s[i] -= 32;
        cout << s[i];
        i++;
    }
    else if (s[i] == '.')
    {
        if (s[i+1] == ' ')
        {
            if (s[i + 2] >= 'a' && s[i + 2] <= 'z')
            {
                s[i + 2] -= 32;
               // cout << s[i + 2];
               
            }
        }
        else
        {
            if (s[i + 1] >= 'a' && s[i] <= 'z')
            {
                s[i + 1] -= 32;
                //cout << s[i + 1];
            }
        }
    }
    cout << s[i];
}

Upvotes: 1

Paul Baxter
Paul Baxter

Reputation: 1175

I think you are over thinking it. You should have a flag for start of sentence and set it to true to start. Then after displaying the letter in upper case reset the flag.

void tosentence(const char *s)
{
    auto startsentense = true;
    for (auto i = 0; s[i]; i++)
    {
        if (startsentense && isalnum(s[i]))
        {
            std::cout << static_cast<char>(toupper(s[i]));
            startsentense = false;
        }
        else if (s[i] == '.')
        {
            std::cout << s[i];
            startsentense = true;
        }
        else
        {
            std::cout << s[i];
        }
    }
}

Upvotes: 1

Related Questions