Can someone explain to me how to properly search for a "tab" character stored in a string class?
For example:
text.txt contents:
std::cout << "Hello"; // contains one tab space
User enters on prompt: ./a.out < text.txt
main.cpp:
string arrey;
getline(cin, arrey);
int i = 0;
while( i != 10){
if(arrey[i] == "\t") // error here
{
std::cout << "I found a tab!!!!"
}
i++;
}
Since there is only one tab space in the textfile, I am assuming it is stored in index [0], but the problem is that I can't seem to make a comparison and I don't know any other way of searching it. Can someone help explain an alternative?
Error: ISO C++ forbids comparison between pointer and integer
First of all, what is i? And secondly, when you use array-indexing of a std::string object, you get a character (i.e. a char) and not a string.
The char is converted to an int and then the compiler tries to compare that int with the pointer to the string literal, and you can't compare plain integers with pointers.
You can however compare a character with another character, like in
arrey[i] == '\t'
std::string::find() might help.
Try this:
...
if(arrey.find('\t') != string::npos)
{
std::cout << "I found a tab!!!!";
}
More info on std::string::find is available here.
Why not using what C++ library provides? You could do it like this:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string arrey;
getline(cin, arrey);
if (arrey.find("\t") != std::string::npos) {
std::cout << "found a tab!" << '\n';
}
return 0;
}
The code is based on this answer. Here is the ref for std::find.
About your edit, how are sure that the input is going to be 10 positions? That might be too little or too big! If it is less than the actual size of the input, you won't look all the characters of the string and if it is too big, you are going to overflow!
You could use .size(), which says the size of the string and use a for loop like this:
#include <iostream>
#include <string>
using namespace std;
int main() {
string arrey;
getline(cin, arrey);
for(unsigned int i = 0; i < arrey.size(); ++i) {
if (arrey[i] == '\t') {
std::cout << "I found a tab!!!!";
}
}
return 0;
}
Related
I cannot figure out how to list out the lines that contain a specified word. I am provided a .txt file that contains lines of text.
So far I have come this far, but my code is outputting the amount of lines there are. Currently this is the solution that made sense in my head:
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
void searchFile(istream& file, string& word) {
string line;
int lineCount = 0;
while(getline(file, line)) {
lineCount++;
if (line.find(word)) {
cout << lineCount;
}
}
}
int main() {
ifstream infile("words.txt");
string word = "test";
searchFile(infile, word);
}
However, this code simply doesn't get the results I expect.
The output should just simply state which lines have the specified word on them.
So, to sum up the solution from the comments. It is just about the std::string's find member function. It doesn't return anything compatible with a boolean, it either return an index if found, or std::string::npos if not found, which is a special constant.
So calling it with traditional way if (line.find(word)) is wrong, but instead, it should be checked this way:
if (line.find(word) != std::string::npos) {
std::cout << "Found the string at line: " << lineCount << "\n";
} else {
// String not found (of course this else block could be omitted)
}
For a school assignment I need to check whether a string entered by the user is stored in a pre-defined word array.
I want to implement a function to perform the check, that may look like this:
bool exists(dict words, char check) { /* how to implement this? */ }
But I have no clue whether this will work or how to implement it. Can anyone help?
Here's my code:
#include <iostream>
#include <string>
using namespace std;
struct dict {
string word;
};
int main() {
dict words[5];
words[0].word = 'abc';
words[1].word = 'bcd';
words[2].word = 'cde';
words[3].word = 'def';
words[4].word = 'efg';
char user_input[100];
cin.getline(user_input, 100);
if (...) { // how do I check if the user input is in my word array?
cout << "found\n";
}
else {
cout << "not found\n";
}
}
First of all, dict is a structure and char is type able to hold single character, so you would rather need to have:
bool exists(const dict* words, const string& check);
From this point, I would say, that:
const dict* should be changed to const vector<dict>&.
std::getline is able to read input directly into string, so no plain char array is needed.
But since it's a school assignment, I suppose, that you have some limitations (and can't use neither std::vector nor std::find, that would do the job). So:
bool exists(const dict* words, size_t count, const std::string& check)
{
for(size_t n = 0; words && (n < count); ++n)
{
if(words[n].word == check)
return true;
}
return false;
}
Example:
dict langs[3];
langs[0].word = "C++";
langs[1].word = "Java";
langs[2].word = "Python";
std::string s_1 = "Java";
std::string s_2 = "C++ 11";
printf("exists(%s) : %s\n", s_1.c_str(), exists(langs, 3, s_1) ? "yes" : "no");
printf("exists(%s) : %s\n", s_2.c_str(), exists(langs, 3, s_2) ? "yes" : "no");
Output:
exists(Java) : yes
exists(C++ 11) : no
Link to sample code.
As the other answer has already pointed out, you should add a size parameter to the function signature in order to be able to iterate the array (especially to know when to stop iteration.). Then a simple loop with a comparison will do the trick.
Note that you shouldn't normally need to use raw arrays in C++, but rather one of the containers from the standard library, e.g., std::vector. Also, you should use std::string and std::getline() for your user input, and you should fix your string literals (use double quotes "..." instead of single quotes '...'). Further, you should avoid using namespace std; conciouslessly. Have a look at the links at the end of this post for some further reading on these points.
Example code:
#include <iostream>
#include <string>
#include <vector>
bool exists(std::string const & user_input,
std::vector<std::string> const & words)
{
for (int i = 0; i < words.size(); i++)
if (user_input == words[i])
return true;
return false;
}
int main() {
std::vector<std::string> words(5);
words[0] = "abc";
words[1] = "bcd";
words[2] = "cde";
words[3] = "def";
words[4] = "efg";
std::string user_input;
std::getline(std::cin, user_input);
if (exists(user_input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
Example output:
$ g++ test.cc && echo "abc" | ./a.out
found
The following might be beyond the scope of your school assignment, but maybe this will be helpful for future visitors to this question.
Note that an array (which std::vector is) is not the most efficient data structure to perform this sort of task, as you have to iterate the entire array to check every single item (linear complexity).
The C++ standard library also provides the container types std::set and std::unordered_set (the latter since C++11). Here the search space is organized in a special way (binary search tree: logarithmic complexity, hash table: constant complexity on average) to improve lookup time of the key type (std::string in this case).
Here's an example:
#include <iostream>
#include <string>
#include <set>
typedef std::set<std::string> set_type;
bool input_exists(std::string input, set_type const & words) {
return words.find(input) != words.end();
}
int main() {
set_type words = {"abc", "bcd", "cde", "def", "efg"};
std::string input;
if (std::getline(std::cin, input)) {
std::cout << "input: '" << input << "' ";
if (input_exists(input, words))
std::cout << "found\n";
else
std::cout << "not found\n";
}
}
Example output:
$ g++ test.cc -std=c++11
$ echo "abc" | ./a.out
input: 'abc' found
$ echo "abcdefg" | ./a.out
input: 'abcdefg' not found
For reference:
http://en.cppreference.com/w/cpp/container/vector
http://en.cppreference.com/w/cpp/string/basic_string
http://en.cppreference.com/w/cpp/string/basic_string/getline
http://en.cppreference.com/w/cpp/language/string_literal
Why is "using namespace std" considered bad practice?
http://en.wikipedia.org/wiki/Binary_search_tree
http://en.wikipedia.org/wiki/Hash_table
http://en.cppreference.com/w/cpp/container/set
http://en.cppreference.com/w/cpp/container/set/find
http://en.cppreference.com/w/cpp/container/unordered_set
http://en.cppreference.com/w/cpp/container/unordered_set/find
http://en.wikipedia.org/wiki/Computational_complexity_theory
I've been doing programming challenges on coderbyte and while doing one, ran into an issue. I want to isolate a word from a string, do some checks on it and then move to another word. The code I'm going to post is supposed to take only the first word and print it out on the screen. When I run it, it doesn't print anything. I thought that maybe I did something wrong in the while loop so I did a simple test. Let's say my input is "This is a test sentence" and instead of word (in cout), I type word[0]. Then it prints "T" just fine. Can you find what the problem is?
#include <iostream>
#include <string>
using namespace std;
int Letters(string str) {
int i=0;
int len=str.length();
string word;
while(i<len){
if(isspace(str[i])){word[i]='\0'; break;}
word[i]=str[i];
i++;
}
cout<<word;
return 0;
}
int main() {
int test;
string str;
getline(cin, str);
test=Letters(str);
return 0;
}
string word;
is default constructed, which is empty initially. Inside while loop, you tried to do:
word[i] = str[i];
It means you tried to access memory that has not been allocated,resulting in undefined behavior.
Try:
word.append(str[i]);
You can use simpler way to get words from input in C++. It will help you to avoid errors in the future.
#include <iostream>
using namespace std;
int main()
{
string word;
while(cin >> word)
{
// "word" contains one word of input each time loop loops
cout << word << endl;
}
return 0;
}
I got a string and I want to remove all the punctuations from it. How do I do that? I did some research and found that people use the ispunct() function (I tried that), but I cant seem to get it to work in my code. Anyone got any ideas?
#include <string>
int main() {
string text = "this. is my string. it's here."
if (ispunct(text))
text.erase();
return 0;
}
Using algorithm remove_copy_if :-
string text,result;
std::remove_copy_if(text.begin(), text.end(),
std::back_inserter(result), //Store output
std::ptr_fun<int, int>(&std::ispunct)
);
POW already has a good answer if you need the result as a new string. This answer is how to handle it if you want an in-place update.
The first part of the recipe is std::remove_if, which can remove the punctuation efficiently, packing all the non-punctuation as it goes.
std::remove_if (text.begin (), text.end (), ispunct)
Unfortunately, std::remove_if doesn't shrink the string to the new size. It can't because it has no access to the container itself. Therefore, there's junk characters left in the string after the packed result.
To handle this, std::remove_if returns an iterator that indicates the part of the string that's still needed. This can be used with strings erase method, leading to the following idiom...
text.erase (std::remove_if (text.begin (), text.end (), ispunct), text.end ());
I call this an idiom because it's a common technique that works in many situations. Other types than string provide suitable erase methods, and std::remove (and probably some other algorithm library functions I've forgotten for the moment) take this approach of closing the gaps for items they remove, but leaving the container-resizing to the caller.
#include <string>
#include <iostream>
#include <cctype>
int main() {
std::string text = "this. is my string. it's here.";
for (int i = 0, len = text.size(); i < len; i++)
{
if (ispunct(text[i]))
{
text.erase(i--, 1);
len = text.size();
}
}
std::cout << text;
return 0;
}
Output
this is my string its here
When you delete a character, the size of the string changes. It has to be updated whenever deletion occurs. And, you deleted the current character, so the next character becomes the current character. If you don't decrement the loop counter, the character next to the punctuation character will not be checked.
ispunct takes a char value not a string.
you can do like
for (auto c : string)
if (ispunct(c)) text.erase(text.find_first_of(c));
This will work but it is a slow algorithm.
Pretty good answer by Steve314.
I would like to add a small change :
text.erase (std::remove_if (text.begin (), text.end (), ::ispunct), text.end ());
Adding the :: before the function ispunct takes care of overloading .
The problem here is that ispunct() takes one argument being a character, while you are trying to send a string. You should loop over the elements of the string and erase each character if it is a punctuation like here:
for(size_t i = 0; i<text.length(); ++i)
if(ispunct(text[i]))
text.erase(i--, 1);
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string str = "this. is my string. it's here.";
transform(str.begin(), str.end(), str.begin(), [](char ch)
{
if( ispunct(ch) )
return '\0';
return ch;
});
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;//string is defined here.
cout << "Please enter a string with punctuation's: " << endl;//Asking for users input
getline(cin, s);//reads in a single string one line at a time
/* ERROR Check: The loop didn't run at first because a semi-colon was placed at the end
of the statement. Remember not to add it for loops. */
for(auto &c : s) //loop checks every character
{
if (ispunct(c)) //to see if its a punctuation
{
c=' '; //if so it replaces it with a blank space.(delete)
}
}
cout << s << endl;
system("pause");
return 0;
}
Another way you could do this would be as follows:
#include <ctype.h> //needed for ispunct()
string onlyLetters(string str){
string retStr = "";
for(int i = 0; i < str.length(); i++){
if(!ispunct(str[i])){
retStr += str[i];
}
}
return retStr;
This ends up creating a new string instead of actually erasing the characters from the old string, but it is a little easier to wrap your head around than using some of the more complex built in functions.
I tried to apply #Steve314's answer but couldn't get it to work until I came across this note here on cppreference.com:
Notes
Like all other functions from <cctype>, the behavior of std::ispunct
is undefined if the argument's value is neither representable as
unsigned char nor equal to EOF. To use these functions safely with
plain chars (or signed chars), the argument should first be converted
to unsigned char.
By studying the example it provides, I am able to make it work like this:
#include <string>
#include <iostream>
#include <cctype>
#include <algorithm>
int main()
{
std::string text = "this. is my string. it's here.";
std::string result;
text.erase(std::remove_if(text.begin(),
text.end(),
[](unsigned char c) { return std::ispunct(c); }),
text.end());
std::cout << text << std::endl;
}
Try to use this one, it will remove all the punctuation on the string in the text file oky.
str.erase(remove_if(str.begin(), str.end(), ::ispunct), str.end());
please reply if helpful
i got it.
size_t found = text.find('.');
text.erase(found, 1);
I am somewhat wondering if I am losing my mind, but I swear to you, this code outputs smiley faces as the .name values!! what in the world is going on? Thus far it seems to only work when the value is 1, anything else properly gives errors.
I realize the code is flawed -> I do not need help with this.
#include <iostream>
#include <fstream>
#include <regex>
#include <string>
#include <list>
using namespace std;
using namespace tr1;
struct CollectedData
{
public:
string name;
float grade;
};
int main()
{
string line;
list<CollectedData> AllData;
int count;
ifstream myFile("test_data.txt");
if (myFile.fail()) {cout << "Error opening file"; return 0;}
else
{
cout << "File opened... \n";
while( getline(myFile, line) ) {
CollectedData lineData;
lineData.name = 1;
lineData.grade = 2;
AllData.push_back(lineData);
}
}
cout << "\n\n File contents: \n";
list<CollectedData>::iterator Iterator;
for(Iterator = AllData.begin();
Iterator != AllData.end();
Iterator++)
{
cout << "\t" << (*Iterator).name << " - ";
cout << "\t" << (*Iterator).grade << "\n";
}
getchar();
return 1;
}
:-) http://img21.imageshack.us/img21/4600/capturekjc.jpg
I KNOW THAT THE CODE IS USELESS,
I WANT TO KNOW WHY IT IS GIVING ME SMILEY FACES INSTEAD OF ERRORS
comforting. . . mocking
I WANT TO KNOW WHY IT IS GIVING ME SMILEY FACES INSTEAD OF ERRORS
Because the datatype is string, and the char 0x01 prints a smile-face. You possibly what to assign the value 0x31 instead, which is the character 1, in ASCII.
The smiling face is the character with ASCII value 1. Not sure why, but apparently your compiler decided to treat it as a char, so you get the smiley.
Your problem is here:
lineData.name = 1;
lineData.grade = 2;
I should note that the symbols you're getting are ASCII 1 (ie, exactly what you're setting lineData.name to).
while( getline(myFile, line) )
You need to take the line and parse it, inserting a proper string into lineData.name, and inserting an integer into lineData.grade.
The string is being assigned a character value (1), which happens to be a smiley face in the ASCII character set.
Like others have said name is of type string, so it would be best to assign a string to it:
lineData.name = "1";
the inverted commas will let the compiler know that this value is a string, and you will stop getting smiley faces.
that said...
Coolest. Bug. Ever.