converting string to sentence case in c++ - 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

Just comment out or remove two lines(becuase they are generating that extra character) and the code will work as you want :
cout << s[i + 2]; and
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];
}

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];
}
}
}

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;
}

Related

Fastest way to count words of string

How could I make this algorithm faster and shorten this code which counts word of given string?
int number_of_words(std::string &s) {
int count = 0;
for (int i = 0; i < s.length(); i++) {
// skip spaces
while (s[i] == ' ' && i < s.length())
i++;
if (i == s.length())
break;
// word found
count++;
// inside word
while (s[i] != ' ' && i < s.length())
i++;
}
return count;
}
Your code is quite alright, speed-wise. But if you want to make your code shorter, you may use find_first_not_of() and find_first_of standard functions, like I did in following code that solves your task.
I made an assumption that all your words are separated by only spaces. If other separators are needed you may pass something like " \r\n\t" instead of ' ' in both lines of my code.
One small optimization that can be made in your code is when you notice that after first while-loop we're located on non-space character, so we can add ++i; line for free before second loop. Similarly after second while-loop we're located on space character so we may add one more ++i; line after second while loop. This will give a tiny bit of speed gain to avoid extra two checks inside while loop.
Try it online
#include <iostream>
#include <string>
int number_of_words(std::string const & s) {
ptrdiff_t cnt = 0, pos = -1;
while (true) {
if ((pos = s.find_first_not_of(' ', pos + 1)) == s.npos) break;
++cnt;
if ((pos = s.find_first_of(' ', pos + 1)) == s.npos) break;
}
return cnt;
}
int main() {
std::cout << number_of_words(" abc def ghi ") << std::endl;
}
Output:
3

What is wrong with my program to find the longest word in a sentence?

#include <iostream>
using namespace std;
int main() {
char a[101]{0};
cin>>a;
cin.getline(a,101);
cin.ignore();
int currLen{0};
int maxLen{0};
int startInd{-1};
int endInd{-1};
for(int i=0; i<101; i++) {
if(a[i]!=' ' ) {
++currLen;
} else if(a[i]==' '||a[i]=='\0') {
if(currLen>maxLen) {
maxLen=currLen;
startInd=i-currLen;
endInd=i-1;
}
if(a[i]=='\0')
break;
currLen=0;
}
}
cout<<maxLen<<endl;
if(startInd==-1)
cout<<-1;
else
for(int i=startInd; i<=endInd; i++)
cout<<a[i];
return 0;
}
If I take an input here, for example, "My name is Manav Kampani"
It will output 5
Manav instead of 7
Kampani
But if I write "My name is Manav Kampani ", with space after the last word
than it is considering Kampani too printing Kampani.
Also when I input "Kampani Manav is my name" then too it's displaying the wrong output. That means it is not considering the first word of the sentence.
if(a[i]!=' ' )
{
++currLen;
}
else if(a[i]==' '||a[i]=='\0')
{
....
}
Consider the case of a[i] == 0. Which of these if-statements will apply.
Answer: the first one. Which means you'll never look at the final word in the string. You also don't exit at the end of the string, but instead loop through whatever is in your string all the way out to character 101.
As a general structure, be very, very careful with this:
if (condition)
else if (condition)
// without a final else section
If you do that, you need to think about what you're doing. In this particular case, you can have:
if (a[i] != 0 && a[i] != ' ')
else
It may not solve all your issues, but it should solve some.
A nice sliding window pattern implementation.
You have 3 problems in your code
You must not write cin >> a;
You must not write cin.ignore();
You need to modify your if statement like so: if (a[i] != ' ' && a[i] != '\0') Otherwise you will not detect the last word.
Your complete working code with that minor fixes will lokk like that.
int main()
{
char a[101]{ 0 };
//cin >> a;
cin.getline(a, 101);
//cin.ignore();
int currLen{ 0 };
int maxLen{ 0 };
int startInd{ -1 };
int endInd{ -1 };
for (int i = 0; i < 101; i++)
{
if (a[i] != ' ' && a[i] != '\0')// Add comparison
{
++currLen;
}
else if (a[i] == ' ' || a[i] == '\0')
{
if (currLen > maxLen)
{
maxLen = currLen;
startInd = i - currLen;
endInd = i - 1;
}
if (a[i] == '\0')
break;
currLen = 0;
}
}
cout << maxLen << endl;
if (startInd == -1)
cout << -1;
else
for (int i = startInd; i <= endInd; i++)
cout << a[i];
return 0;
}
Additionally. You should not use C-Style arrays in C++. And please use std::string
There is a couple of things here:
1- You don't need to do a cin>>a this is actually consuming the first word, and afterwards the content is overrided by cin.getline(). So removing the firsst cin>>ayou'll be fine.
2- The last word is not read because there isn't any if condition that matches the condition aka.
if(a[i]!=' ' ) case of not a space
//not end of word
else if(a[i]==' '||a[i]=='\0') case of space or null
//end of word
So your last character is not a space nor null, that means you don't detect the last word.

How to deduplicate a string where it only deletes consecutive duplicates

The goal of the program is to take a string like "kcck" and delete the consecutive duplicates. It should first iterate through the string and delete cc leaving kk; then go through again and delete kk; then return "empty" since there are no characters left in the string.
Another example, "aabggtcc" should return "bt".
int i;
int j = i+1;
string deduplicate(string input) {
for(i=0; i<input.length(); ++i) {
while(j <input.length()) {
if(input[i] == input[j]) {
input.erase(i);
input.erase(j);
}
else if (input[i] != input[j]) {
++i; ++j;
}
if(input[i] == '\0') {
cout<<"empty";
}
}
}
return 0;
}
int main () {
cout<<deduplicate("aabg")<<endl;
cout<<deduplicate("ag")<<endl;
cout<<deduplicate("btaabb")<<endl;
return 0;
}
When I run the code it gives me:
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string
There are couple of issues with your snippet,
deduplicate function is returning zero(0) all the time
j is initialized in global scope and is never reset for new string
As you erase std::string::length() is calculated on new string hence your index i and j are won't point to same laocation.
Here is the snippet with rectified error,
string deduplicate(string input) {
int i = 0;
int j = 0;
while (i < input.length()) {
j = i + 1;
bool isRepeated = false;
while (j < input.length()) {
if (input[i] == input[j]) {
input.erase(j,1);
--j; //as string length is reduced by 1
isRepeated = true;
}
++j;
}
if (isRepeated) {
input.erase(i,1); //remove first letter as well
--i;//sting length is reduced by one
}
++i;
}
return input;
}
int main() {
std::cout << deduplicate("aabg") << endl;
std::cout << deduplicate("ag") << endl;
std::cout << deduplicate("btaabb") << endl;
return 0;
}
output:
bg
ag
t
which can be even simplified as,
std::string deduplicate(std::string input) {
std::string s ="";
for (auto c : input) //loop through all char
{
int f = 0;
for (auto c1 : input)
{
if (c1 == c)
{
f++; //increment if char is found
}
}
if (f == 1)//append char only if it present ones
s += c;
}
return s;
}
You are decreasing the size of the string whenever you call string.erase() that's why the variable i eventually exceeds the "current" string size input.length() in the while loop, and you get an error std::out_of_range: basic_string when you try to access input[i] in the if and else if conditions of the loop.
Try to manually go through the loop on the string on which you got the error and you will see that i has gone out of bound (i.e. i >= input.length()) in the while loop
With C++11 and on, instead of iterating over each character and making the comparison manually, you can use std::basic_string::find_first_not_of to look forward from a position in the string and find the first character not of the current character. If the position returned by .find_first_not_of is more than 1 from the current position, you can use .erase to erase that number characters. If the return is 1, then just increment your current position and repeat.
To operate on all duplicates characters in the modified string, you simply wrap it all in an outer-loop, keep a copy of the string before before entering the inner-loop to remove duplicate characters, and compare if the modified string is equal to your copy or the .length() is zero for your exit condition.
You can do something similar to the following:
#include <iostream>
#include <string>
int main (void) {
std::string s;
while (getline (std::cin, s)) {
std::string current;
do {
size_t pos = 0;
current = s;
while (pos < s.length()) {
size_t duplicates = s.find_first_not_of (s.at(pos), pos);
if (duplicates != std::string::npos && duplicates > pos + 1)
s.erase(s.begin() + pos, s.begin() + duplicates);
else if (duplicates == std::string::npos &&
(s.end() - s.begin() - pos) > 1)
s.erase(s.begin() + pos, s.end());
else
pos++;
}
} while (current != s && s.length());
std::cout << "'" << s << "'\n";
}
}
Example Use/Output
$ echo "kcck" | ./bin/ddcpp
''
$ echo "aabggtcc" | ./bin/ddcpp
'bt'
$ echo "aabg" | ./bin/ddcpp
'bg'
$ echo "ag" | ./bin/ddcpp
'ag'
$ echo "btaabb" | ./bin/ddcpp
'bt'
There are a number of ways to approach the problem and as long as they are reasonably efficient there isn't any one right/wrong way. If you have a modern C++ compiler, letting some of the built-in container functions handle the work is generally a bit more robust than reinventing it on your own. Look things over and let me know if you have questions.

how to calculate polynomial (x^2^2^2^2+x^2^2^2)

I want to calculate (x^2^2^2^2+x^2^2^2) result should be [x^256+x^16]..but i am unable to do this completely..i also have written a code which is working for first half(before '+') but in other half it fails to do it...
#include<iostream>
#include<string>
#include <algorithm>
#include<sstream>
using namespace std;
int main()
{
string a;
cin >> a;
string s1 = "^";
string::size_type foud;
foud = a.find(s1);
int i = foud;
int flag = 0;
i++;
while (foud != std::string::npos)
{
flag = 0;
cout << i <<"I"<< endl;
while (flag != 1 && i < a.length())
{
if (a[i] == '(' || a[i] == '+' || a[i] == '-' || a[i] == ')')
{
flag++;
cout << "terminator" << endl;
}
else if (a[i] == '^')
{
/*int j = (int)(a[i - 1]);
j = j - 48;
int k = (int)(a[i + 1]);
k = k - 48;
i = k + 1;
int power =0;
power = pow(j, k);
;*/
int j = i;
int k = i;
k--;
j++;
string bcknumber;
while (a[k] != '^' && a[k] != '(' && a[k] != '+' && a[k] != '-' && a[k] != ')')
{
bcknumber = bcknumber + a[k];
k--;
}
cout << bcknumber << endl;
reverse(bcknumber.begin(), bcknumber.end());
cout << bcknumber << endl;
int BK;
BK = stoi(bcknumber);
int FD;
string frdnum;
while (a[j] != '^'&&a[j] != '\0' && a[j] != '(' && a[j] != '+' && a[j] != '-' && a[j] != ')')
{
frdnum = frdnum + a[j];
j++;
}
FD = stoi(frdnum);
int resil = pow(BK, FD);
frdnum.clear();
stringstream s;
string res;
s << resil;
res = s.str();
if (i == 15)
{
a.replace(14, 15, res);
}
else
{
a.replace(i - bcknumber.length(), i + frdnum.length(), res);
}
i--;
bcknumber.clear();
}
else
i++;
}
foud = a.find("^", foud + 1);
i = foud;
i++;
}
cout << a << endl;
system("pause");
}
This is not a trivial problem. You want to build an infix calculator (a + b). A prefix calculator (+ a b) or a postfix calculator (a b +) are simpler, since there are no ambiguities at all. An infix calculator can have a lot of them, depending on the degree of freedom you want the user to have.
In the problem you're exposing, one is tempted to say: well, if there is an operator next to the second operand, then I have to accumulate the last result and operate with that and the next operation. However, there are problems like precedence which will not be deal with with that approach.
I would start creating a prefix calculator. It is a lot easier:
calculate():
opr = match operator
op1 = match operand
if op1 is operator:
back
op1 = calculate
op2 = match operand
if op2 is operator:
back
op2 = calculate
return calc(opr, op1, op2)
Once you have mastered that, then there is the possibility to start with an infix calculator.
One thing to do in the last algorithm would be to change it to avoid recursion, for example.
This is a good exercise, enjoy it. Hope this helps.
This smells like homework/assignment so I will not provide code...
As I see it you want just string parser to string replacing the power part. I am assuming You still do not understand the power math or are wrongly writing/interpreting representation of the string. For example:
x^2^2^2^2 =
(((x^2)^2)^2)^2 =
(((x.x)^2)^2)^2 =
((x.x).(x.x))^2)^2 =
((x.x.x.x))^2)^2 =
((x.x.x.x).(x.x.x.x))^2 =
(x.x.x.x.x.x.x.x)^2 =
(x.x.x.x.x.x.x.x).(x.x.x.x.x.x.x.x) =
(x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x) =
x^16
And not yours x^256. You can not add parenteses where you want they must be placed according to order of math operations otherwise the resulting equation will not match the input string !!!. In case you got defined different parse rules for your parser then in standard math then you need to define them in the Question.
Now how to approach this:
read string
I would start with constant hard-coded string instead of typing it all the time while programing/debugin over and over (as many students do ... I saw few times people typing 5x5 matrix on each build :) ... which is insane)
When the program works only then use the cin reading... as you already do
detect which part of the string is power exponent
exponent=1
Search the string for first ^ and remember the start position i0 if not found goto #4.
Now depending on what follows:
If number multiply exponent by it.
If ^ skip it and goto to #2
if neither stop
Of coarse if you should support parentes then it will be much much more complicated and you need to decode the whole thing which is not trivial which you should also mention in the Question.
replace original exponent string with computed string (if computable)
so the computed string will be "^"<<exponent or "^"+exponent depends on what kind of string arithmetics you using ....
output string
with cout or whatever as you already do

Strings over 15 characters get turned to ε■ε■ε■ε■ε■ε■ε■ε■ε

I have been implementing a factory for a component based game engine recently. I am deserializing objects by reading in from a file what component they need and what to initialize them with. It works except for when I try to read in a property longer than 15 characters. At 15 characters, it reads it in perfectly, anything longer and I get "ε■ε■ε■ε■ε■ε■ε■ε■ε" as output.
I am using std::string to store these lines of text.
Example:
JunkComponent2 test "1234567890123456" test2 "123456789012345"
With this the value of test becomes garbage, while test2 stays perfectly intact.
Any idea's what might be going on?
char line[1024];
while (file.getline(line, 1024))
{
std::vector<std::string> words;
std::string word;
int j = 0;
for (unsigned i = 0; line[i] != '\0' && i < 1024; ++i)
{
if (line[i] == ' ' && j > 0 && line[i - 1] != '\\')
{
words.push_back(word);
j = 0;
word = "";
}
else
{
++j;
word += line[i];
}
}
words.push_back(word);
// std::cout << (*Parts)["JunkComponent"]->GetName() << std::endl;
Component* c = (*Parts)[words[0]]->clone(words);
object->AddComponent(words[0], c);
for (std::list<Member*>::iterator it = members.begin(); it != members.end(); ++it)
{
for (unsigned i = 0; i < words.size(); ++i)
{
if ((*it)->GetName() == words[i])
{
if (words[i + 1][0] == '\"')
{
std::vector<char> chars;
chars.push_back('\"');
chars.push_back('\\');
for (unsigned int n = 0; n < chars.size(); ++n)\
{
words[i + 1].erase(std::remove(words[i + 1].begin(), words[i + 1].end(), chars[n]), words[i + 1].end());
}
Container((*it)->GetMeta(), GET_MEMBER(data.GetData(), (*it)->GetOffset()), (*it)->GetName()).SetValue<std::string>(words[i + 1]);
}
else
{
Container((*it)->GetMeta(), GET_MEMBER(data.GetData(), (*it)->GetOffset()), (*it)->GetName()).SetValue<int>(std::stoi(words[i + i]));
}
++i;
break;
}
}
}
}
GET_MEMBER Macro expands to:
#define GET_MEMBER(P, OFFSET) ((void *)(((char *)(P)) + (OFFSET)))
SetValue Function: (data is a void*)
template <typename T>
void SetValue(T data_)
{
memcpy(data, &data_, sizeof(T));
}
I'll take a stab having just eyed your code. GET_MEMBER is really nasty and I think that's where your problem is. It seems to rely on std::string being convertible to char*, which it is not. Why does your code work with strings shorter than 15? Well that's more than likely because std::string on most popular implementations actually contains a special case for strings where it keeps an internal buffer of length 16 ( last element \0 ) to avoid dynamic memory allocation. When the string is larger than 15 this buffer is uninitialized because it isn't used. The correct way to access the string is by using operator[].