How does "to_string" work in array of string? - c++

I want to combine the first 4 characters of each line in txt file and compare it with the keyword I have, but
when I combine the characters, I get the sum of these 4 characters' ascii numbers(whatever).
How can I solve this problem. My code is here:
When I debuged, I saw the string search(variable) was 321.
int main() {
ifstream file("sentence.txt");
if (file.is_open()) {
string line;
while (getline(file, line)) {
string search = to_string(line[0] + line[1] + line[2]); // you see what I mean
if ("dog" == search) {
cout << "there is dog";
}
else {
cout << "there is no dog"<<endl;
}
}
}
}

The function std::to_string() is designed to convert a number into a string representation. It is not what you need.
There is no need to create the new string search to check whether the string line starts with the string "dog".
Creating the new string search is inefficient.
Instead, you could write for example
if ( line.compare( 0, 3, "dog" ) == 0 ) {
cout << "there is dog";
}
else {
cout << "there is no dog" << endl;
}
Or, if your compiler supports C++20, you can also write:
if ( line.starts_with( "dog" ) ) {
cout << "there is dog";
}
else {
cout << "there is no dog" << endl;
}

line[0], line[1], and line[2] are chars, not std::strings. char is an integer type, so adding two chars together results in a single integer that is the sum of the two operands. It does not produce a std::string that is the concatenation of the two chars.
To get a substring of a std::string use the substr member function:
std::string search = line.substr(0, 3);
Or, if you actually need to construct a std::string from individual chars, use the constructor that accepts a std::initializer_list<char>:
std::string search{line[0], line[1], line[2]};

A string made from the first characters of line can be obtained via std::substr. In this case I'd actually prefer the constructor that takes two iterators:
std::string first3chars{line.begin(),line.begin()+3};
Take care of lines that are less than 3 characters.
Your code adds the values of three chars. Adding chars via + does not concatenate them, and if it would why call std::to_string on the result? char is an integer type and what you see as 321 is the result of adding the number representations of the first 3 characters in line.

Is there a way for you to cast those chars (which appear to be integer type for some reason) into char type once again. Perhaps that ought to resolve the issue in case the "to_string" concatenates those 3 inputs into one; additionally intelli-sense should do the trick of explaining parameter usage and returning value.

The problem with this code is that when you access an element of a string you get a character which is an ASCII number, when you try to sum two characters you are adding their ASCII codes.
In your specific case, as you want sequential characters, the best solution would probably be to use the substr function (documentation) for strings. Otherwise, you would probably need to convert one of the characters to a string and then “add” the other characters to it.

Related

Why when a character array is compared to another character array, output is wrong but when character array is compared to a string output is correct? [duplicate]

This question already has an answer here:
C++ string and string literal comparison
(1 answer)
Closed 1 year ago.
Question - The translation from the Berland language into the Birland language is not an easy task. Those languages are very similar: a berlandish word differs from a birlandish word with the same meaning a little: it is spelled (and pronounced) reversely. For example, a Berlandish word code corresponds to a Birlandish word edoc. However, it's easy to make a mistake during the «translation». Vasya translated word s from Berlandish into Birlandish as t. Help him: find out if he translated the word correctly.
Input -
The first line contains word s, the second line contains word t. The words consist of lowercase Latin letters. The input data do not consist unnecessary spaces. The words are not empty and their lengths do not exceed 100 symbols.
Output -
If the word t is a word s, written reversely, print YES, otherwise print NO.
When I write this code, the output is wrong -
int main(){
char s[100000],a[100000];
cin >> s >> a;
strrev(s);
if(s==a){
cout << "YES";
}else{cout << "NO";}
}
But when I write this code, the output is correct -
int main(){
char s[100000];
string a;
cin >> s >> a;
strrev(s);
if(s==a){
cout << "YES";
}else{cout << "NO";}
}
Why is it like this, is there a rule that a character array cannot be compared to another character array and if so, how can it be compared to a string?
Remember that arrays naturally decay to pointers to their first elements, and it's such pointers that you are comparing.
In short, what you're really doing is:
if(&s[0] == &a[0])
And those two pointers will never be equal.
To compare the contents of character arrays, you need to use strcmp() or similar function instead, eg:
if(strcmp(s, a) == 0)
Since you're programming in C++, please use std::string for all your strings. There are overloads for the == operator that do the right thing if you have std::string values.

How to arrange the loops to check for numbers

I have a program that reads a credit card number. I want to add in something that makes sure that 16 numbers are added in, no letters, and as many spaces as wanted (although they don't count towards numbers). Is there a function or set of functions to do this, or should I just make a bunch of while and if loops that use isdigit() and isalpha() that goes through the array one element at a time?
char cardNum[32];
cout << "Enter credit card number: ";
cin.getline(cardNum, 32); //Read in the entire line for the name
There are numerous things you could do. One idea is to use std::find_if with a custom predicate. For example:
bool IsCharIllegal(char ch)
{
// return true or false based on whatever your exact requirements are
}
Then:
auto itFound = std::find_if(cardNum, cardNum + 32, IsCharIllegal);
if(itFound != cardNum + 32)
// invalid character was entered!
There is a case to be made for using std::string instead of a raw char array too:
std::string cardNum;
cout << "Enter credit card number: ";
std::cin >> cardNum;
Followed by:
auto itFound = std::find_if(cardNum.begin(), cardNum.end(), IsCharIllegal);
if(itFound != cardNum.end())
// invalid character was entered!
That helps avoid the magic 32 and also allows inputs of any length.
I would use a regular expression to match this pattern. If you're using C++11, you can use the built in header: http://www.cplusplus.com/reference/regex/
Otherwise, take a look here for some alternative libraries you can use: C++: what regex library should I use?
Unfortunately, I'm not very good at regular expressions, but the following should match 16 numbers with spaces inbetween.
(\d[ ]*){16}
If you're looking for more info on regular expressions, here is a good cheat sheet I use often: http://regexlib.com/CheatSheet.aspx
I also like to test my expressions using this site: http://regexpal.com/
So something like this would be allowed?
"123 456 789 01 23456"
Use std::string and the free-standing std::getline function. It's better than the member function of the same name, because it doesn't force you to deal with pointers.
std::string line;
std::getline(std::cin, line);
if (!std::cin)
{
// catastrophic input failure
}
Then you have a string as in my example above in line. You could use std::find_if to verify that there are no illegal characters and std::count_if to make sure there are exactly 16 digits, but I think writing your own loop (not "bunch of loops") would yield more readable code here.
By the way, beware of isdigit! For historical reasons, you must cast its argument to unsigned char in order to use it safely.
There is an atoll function in the cstdlib. http://www.cplusplus.com/reference/cstdlib/atoll/
It converts character string input into a long long, which could store a 16 digit long credit card number, however this quits as soon as there's an non-numeric character in the input so
atoll("123456abc890")
would return 123456
If you want to check each character by character, you could just use atoi on each character then reassemble the string for each character that passes.
http://www.cplusplus.com/reference/cstdlib/atoi/

C++ string parsing

All:
I got one question in string parsing:
For now, if I have a string like "+12+400-500+2:+13-50-510+20-66+20:"
How can I do like calculate total sum of each segment( : can be consider as end of one segment). For now, what I can figure out is only use for to loop through and check +/- sign, but I do not think it is good for a Universal method to solve this kind of problem :(
For example, the first segment, +12+400-500+2 = -86, and the second segment is
+13-50-510+20-66+20 = -573
1) The number of operand is varied( but they are always integer)
2) The number of segment is varied
3) I need do it in C++ or C.
I do not really think it as a very simple question to most newbie, and also I will claim this is not a homework. :)
best,
Since the string ends in a colon, it is easy to use find and substr to separate out parts of the string partitioned by ':', like this:
string all("+12+400-500+2:+13-50-510+20-66+20:");
int pos = 0;
for (;;) {
int next = all.find(':', pos);
if (next == string::npos) break;
string expr(all.substr(pos, (next-pos)+1));
cout << expr << endl;
pos = next+1;
}
This splits the original string into parts
+12+400-500+2:
and
+13-50-510+20-66+20:
Since istreams take leading plus as well as leading minus, you can parse out the numbers using >> operator:
istringstream iss(expr);
while (iss) {
int n;
iss >> n;
cout << n << endl;
}
With these two parts in hand, you can easily total up the individual numbers, and produce the desired output. Here is a quick demo.
You need to seperate operands and operators. To do this you can use two queue data types one for operands and one for operators
split by :, then by +, then by -. translate into int and there you are.
Your expression language seems regular: you could use a regex library - like boost::regex - to match the numbers, the signs, and the segments in groups directly, with something like
((([+-])([0-9]+))+)(:((([+-])([0-9]))+))+

Efficiently appending or inserting a variable number of spaces to a string

I have a simple programme that inserts or appends a number of spaces to align text.
f()
{
string word = “This word”;
const string space = “ “;
int space_num = 5; // this number can vary
for (int i = 0; i < space_num; i++)
{
word.insert(0, space);
}
cout << word;
}
Now this works, but I was wondering if there was a more efficient way to do this. Not in terms of optimizing my programme, but more as in standard practice.
I can imagine two potential methods:
1 - Is there a way to create a string of say 20 spaces, and append a portion of those spaces rather than repeatedly adding a single space.
2 – Is there a way to create string with a variable number of spaces and append that?
Yes, both take a number of copies and a character:
word.insert(0, space_num, ' ');
word.append(space_num, ' ');
For aligning text, keep in mind you can use a string stream and the <iomanip> header, such as std::setw as well.
1 - Is there a way to create a string of say 20 spaces, and append a portion of those spaces rather than repeatedly adding a single space.
Yes, try this:
string spaces(20, ' ');
string portionOfSpaces = spaces.substr(0,10); //first 10 spaces
string newString = portionOfSpaces + word;
Generally, you can use substr to get a portion of spaces and do operations with that substring.
2 – Is there a way to create string with a variable number of spaces and append that?
Yes, see string constructor:string (size_t n, char c); and string::append

Getting Stringstream to read from character A to B in a String

Is there some way to get StringStream to read characters A through B of a string?
For example, something like (but not):
stringstream mystringstream;
mystringstream.read(char* s, streamsize n, **int firstcharacter**);
Thanks for your help.
EDIT: By A through B I mean, for example, the third through fifth characters.
EDIT: Example: get characters three through five of "abcdefghijklmnop" would give "cde".
or, if you need a substring in position A through B, you can do
string s = mystring.substr(A, B-A+1); // the second parameter is the length
if this must be a stringstream, you can do
string s = mystringstream.str().substr(A, B-A+1);
You can use the substr-method:
std::string foo = "asdfersdfwerg";
std::cout << foo.substr(5, 4) << std::endl;
This will print rsdf.