I'm trying to compare a char * to a to a std::string
const char *s = "0#s072116\tblah\tblah\blah";
std::string id = "072116";
I need to compare these two, basically before the first \t and after the first 3 chars on the left. The width of the id can vary. :(
I'm not very good at C++. Any ideas??
Thanks
You can do it as follows:
#include <iostream>
#include <string>
using namespace std;
...
int main() {
const char *s = "0#s072116\tblah\tblah\blah";
string ss = s;
string id = "072116";
int found = ss.find(id);
cout << "found is: " << found;
}
If id is a substring in ss, then found will be the position of the first occurrence of id in ss.
If id is not a substring in ss, then found will be a negative number.
More examples on find.
Caveat:
The code above is based on the assumption your meant "...basically before the first \t and after the first 3 chars on the left..." as a way to point out where the substring would be matched in this particular example.
If instead it is a requirement that must be met for all instances (i.e. const char *s = "0#s\tblah\tblah\blah072116" should not be matched), then the provided code sample is not sufficient.
const char *position = std::search(s, s + std::strlen(s), id.begin(), id.end());
if (*position == '\0')
std::cout << "Not found\n";
else
std::cout << "Found at offset " << (position - s) << '\n';
Related
I'm working on a program that takes user input two times. The user will input a sentence, and then enter a key phrase to remove each found match throughout the sentence, and return what's left. The code I have below for the 'logic' is...
char delim[AFFIX];
strcpy(delim, userInput); //storing the phrase user wants to remove
char *token = strtok(sentence, delim);
while (token)
{
cout << token << endl;
token = strtok(NULL, delim);
}
The issue I'm having is that strtok removes every single instance of a character found. For example, if the user wishes to remove all instances of 'pre' then the word "preformed" would turn into "fo m d" instead of formed. Is there a way to restrict strtok from removing EVERY instance of a character found, and only remove the series of characters?
I understand that working with strings or vectors would make my life much easier, but I want to work with arrays of chars. I'm really sorry if this isn't clear enough, I'm very new to c++. Any advice on how to approach this problem would be greatly appreciated. Thank you for your time.
A easy and more or less dirty solution would be to just add spaces before and after your search word. To ensure it's actually a full word and not part of a word.
Eg:
Input: "pre"
Check: " pre "
To ensure you also cut the first word you would need to check the first part of the string and add a space before it if the first word is also the inputted word.
Example:
#include <string>
#include <iostream>
void removeSubstrs(std::string& s, std::string& p) {
std::string::size_type n = p.length();
for (std::string::size_type i = s.find(p);
i != std::string::npos;
i = s.find(p))
s.erase(i, n);
}
void check(std::string& s, std::string& p) {
int slen = s.length();
int plen = p.length();
std::string firstpart = s.substr (0,plen);
std::string lastpart = s.substr (slen-plen,slen);
if (firstpart == p) {
s = " " + s;
}
if (lastpart == p) {
s += " ";
}
}
int main ()
{
std::string str = "pre test inppre test pre";
std::string search = "pre";
std::string pattern = " " + search + " ";
check(str, search);
removeSubstrs(str, pattern);
std::cout << str << std::endl;
return 0;
}
strtok isn't the right choice here, you can think of strtok's 2nd argument as a list of delimiters (each char in that list is a delimiter) and it breaks the string into tokens using those delimiters.
A better solution would be something along the lines of strstr and strcat.
maybe something like this (using MSVC++)
void removeSubstr(char *string, const char *sub, int n) {
char *match;
int len = strlen(sub);
while ((match = strstr(string, sub))) {
*match = '\0';
strcat_s(string, n, match + len);
}
}
int main() {
char test[] = "abcxyz123xyz";
removeSubstr(test, "xyz", sizeof(test) / sizeof(char));
cout << test << endl;
}
strcat_s is a more secure version of strcat (MSVC++ likes it way more than strcat :p)
There are better ways of doing this ofc but I'm restricting myself to char arrays here as you requested...
I have this code and I want to insert a new line after each dot with a insert statement. I get the error message no matching member function for call to 'insert'. What am I doing wrong?
#include<iostream>
#include<string>
using namespace std;
int main ()
{
string const inText1 = "I'm reading. ";
string const inText2 = "I like to read. ";
string const inText3 = "I'm gonna read that book. ";
string const inText4 = "She's reading. ";
string const inText5 = "He's reading. ";
string const inText6 = "READ. ";
string const inText7 = "Reading. ";
string inText8=inText1+inText2+inText3+inText4+inText5+inText6+inText7;
string::size_type dotpos = inText10.find(".");
if(dotpos != string::npos)
inText10.insert(dotpos, endl);
cout << inText10 << endl;
return 0;
}
Assuming inText10 is just inText8, this is the working code.
Changes done:
Earlier, the inText10 string was not found. So, insert() on that object might have produced your error.
The position to insert newline is NOT dotpos. Its dotpos + 1
Note this code just adds a newline after finding the first dot. To add newline after every dot, use while loop to find all dots and insert newline char next to it.
#include<iostream>
#include<string>
using namespace std;
int main ()
{
string const inText1 = "I'm reading. ";
string const inText2 = "I like to read. ";
string const inText3 = "I'm gonna read that book. ";
string const inText4 = "She's reading. ";
string const inText5 = "He's reading. ";
string const inText6 = "READ. ";
string const inText7 = "Reading. ";
string inText8=inText1+inText2+inText3+inText4+inText5+inText6+inText7;
string::size_type dotpos = inText8.find(".");
if(dotpos != string::npos)
inText8.insert(dotpos + 1, "\n");
cout << inText8 << endl;
return 0;
}
There are a lot of undefined variables in your code, but basically you receive 'no matching member function for call to 'insert'' because you are trying to insert std::endl into a string. std::endl can't be casted to char of any type, so, you can't do this.
To fix your issue, replace
inText10.insert(dotpos, endl);
with
inText10.insert(dotpos, '\n');
By the way, if you want to insert \n after every single dot, you should do find() in a loop, since find() returns a single matched char position, not an array.
To learn more, why you can't insert std::endl, read this std::endl description at cppreference
Let's say I have
string sentence{"Hello how are you."}
And I want string sentence to have "how are you" without the "Hello". How would I go about doing that.
I tried doing something like:
stringstream ss(sentence);
ss>> string junkWord;//to get rid of first word
But when I did:
cout<<sentence;//still prints out "Hello how are you"
It's pretty obvious that the stringstream doesn't change the actual string. I also tried using strtok but it doesn't work well with string.
Try the following
#include <iostream>
#include <string>
int main()
{
std::string sentence{"Hello how are you."};
std::string::size_type n = 0;
n = sentence.find_first_not_of( " \t", n );
n = sentence.find_first_of( " \t", n );
sentence.erase( 0, sentence.find_first_not_of( " \t", n ) );
std::cout << '\"' << sentence << "\"\n";
return 0;
}
The output is
"how are you."
str=str.substr(str.find_first_of(" \t")+1);
Tested:
string sentence="Hello how are you.";
cout<<"Before:"<<sentence<<endl;
sentence=sentence.substr(sentence.find_first_of(" \t")+1);
cout<<"After:"<<sentence<<endl;
Execution:
> ./a.out
Before:Hello how are you.
After:how are you.
Assumption is the line does not start with an empty space. In such a case this does not work.
find_first_of("<list of characters>").
the list of characters in our case is space and a tab. This will search for first occurance of any of the list of characters and return an iterator. After that adding +1 movers the position by one character.Then the position points to the second word of the line.
Substr(pos) will fetch the substring starting from position till the last character of the string.
You can for example take the remaining substring
string sentence{"Hello how are you."};
stringstream ss{sentence};
string junkWord;
ss >> junkWord;
cout<<sentence.substr(junkWord.length()+1); //string::substr
However, it also depends what you want to do further
There are countless ways to do this. I think I would go with this:
#include <iostream>
#include <string>
int main() {
std::string sentence{"Hello how are you."};
// First, find the index for the first space:
auto first_space = sentence.find(' ');
// The part of the string we want to keep
// starts at the index after the space:
auto second_word = first_space + 1;
// If you want to write it out directly, write the part of the string
// that starts at the second word and lasts until the end of the string:
std::cout.write(
sentence.data() + second_word, sentence.length() - second_word);
std::cout << std::endl;
// Or, if you want a string object, make a copy from the start of the
// second word. substr copies until the end of the string when you give
// it only one argument, like here:
std::string rest{sentence.substr(second_word)};
std::cout << rest << std::endl;
}
Of course, unless you have a really good reason not to, you should check that first_space != std::string::npos, which would mean the space was not found. The check is omitted in my sample code for clarity :)
You could use string::find() to locate the first space. Once you have its index, then get the sub string with string::substr() from the index after the index of the space up to the end of the string.
One liner:
std::string subStr = sentence.substr(sentence.find_first_not_of(" \t\r\n", sentence.find_first_of(" \t\r\n", sentence.find_first_not_of(" \t\r\n"))));
working example:
#include <iostream>
#include <string>
void main()
{
std::string sentence{ "Hello how are you." };
char whiteSpaces[] = " \t\r\n";
std::string subStr = sentence.substr(sentence.find_first_not_of(whiteSpaces, sentence.find_first_of(whiteSpaces, sentence.find_first_not_of(whiteSpaces))));
std::cout << subStr;
std::cin.ignore();
}
Here's how to use a stringstream to extract the junkword while ignoring any space before or after (using std::ws), then get the rest of the sentence, with robust error handling....
std::string sentence{"Hello how are you."};
std::stringstream ss{sentence};
std::string junkWord;
if (ss >> junkWord >> std::ws && std::getline(ss, sentence, '\0'))
std::cout << sentence << '\n';
else
std::cerr << "the sentence didn't contain ANY words at all\n";
See it running on ideone here....
#include <iostream> // cout
#include <string> // string
#include <sstream> // string stream
using namespace std;
int main()
{
string testString = "Hello how are you.";
istringstream iss(testString); // note istringstream NOT sstringstream
char c; // this will read the delima (space in this case)
string firstWord;
iss>>firstWord>>c; // read the first word and end after the first ' '
cout << "The first word in \"" << testString << "\" is \"" << firstWord << "\""<<endl;
cout << "The rest of the words is \"" <<testString.substr(firstWord.length()+1) << "\""<<endl;
return 0;
}
output
The first word in "Hello how are you." is "Hello"
The rest of the words is "how are you."
live testing at ideon
I've been looking thousand of questions and answers about what I'm going to ask, but I still didn't find the way to do what I'm gonna to explain.
I have a text file from which I have to extract information about several things, all of them with the following format:
"string1":"string2"
And after that, there is more information, I mean:
The text file is something like this:
LINE 1
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string1":"string2"XXXXXXXXXXXXXXXXXXXXXXXXXX"string3":"string4"XXXXXXXXXXXXXXXXXXXXXXXXXXXX...('\n')
LINE 2
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string5":"string6"XXXXXXXXXXXXXXXXXXXXXXXXXX"string7":"string8"XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
XXX represents irrelevant information I do not need, and theEntireString (string used in the code example) stores all the information of a single line, not all the information of the text file.
I have to find first the content of string1 and store the content of string2 into another string without the quotes. The problem is that I have to stop when I reache the last quote and I don't know how exactly do this. I suppose I have to use the functions find() and substr(), but despite having tried it repeatedly, I did not succeed.
What I have done is something like this:
string extractInformation(string theEntireString)
{
string s = "\"string1\":\"";
string result = theEntireString.find(s);
return result;
}
But this way I suppose I store into the string the last quote and the rest of the string.
"find" function just give you the position of matched string to get the resulting string you need to use the "subst" function. Try This
string start,end;
start = theEntireString.substr(1,theEntireString.find(":")-2);
end = theEntireString.substr(theEntireString.find(":")+2,theEntireString.size()-1);
That will solve you problem
Assuming either the key or value contains a quotation mark. The following will output the value after the ":". You can also use it in a loop to repeatedly extract the value field if you have multiple key-value pairs in the input string, provided that you keep a record of the position of last found instance.
#include <iostream>
using namespace std;
string extractInformation(size_t p, string key, const string& theEntireString)
{
string s = "\"" + key +"\":\"";
auto p1 = theEntireString.find(s);
if (string::npos != p1)
p1 += s.size();
auto p2 = theEntireString.find_first_of('\"',p1);
if (string::npos != p2)
return theEntireString.substr(p1,p2-p1);
return "";
}
int main() {
string data = "\"key\":\"val\" \"key1\":\"val1\"";
string res = extractInformation(0,"key",data);
string res1 = extractInformation(0,"key1",data);
cout << res << "," << res1 << endl;
}
Outputs:
val,val1
Two steps:
First we have to find the position of the : and splice the string into two parts:
string first = theEntireString.substr(0, theEntireString.find(":"));
string second = theEntireString.substr(theEntireString.find(":") + 1);
Now, we have to remove the "":
string final_first(first.begin() + 1, first.end() - 1);
string final_second(second.begin() + 1, second.end() - 1);
You don't need any string operation. I hope the XXXXX doesn't contain any '"', so You can read the both strings directly from the file:
ifstream file("input.txt");
for( string s1,s2; getline( getline( file.ignore( numeric_limits< streamsize >::max(), '"' ), s1, '"' ) >> Char<':'> >> Char<'"'>, s2, '"' ); )
cout << "S1=" << s1 << " S2=" << s2 << endl;
the little help-function Char is:
template< char C >
std::istream& Char( std::istream& in )
{
char c;
if( in >> c && c != C )
in.setstate( std::ios_base::failbit );
return in;
}
#include <regex>
#include <iostream>
using namespace std;
const string text = R"(
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string1":"string2"XXXXXXXXXXXXXXXXXXXXXXXXXX"string3" :"string4" XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
XXXXXXXXXXXXXXXXXXXXXXXXXXXX"string5": "string6"XXXXXXXXXXXXXXXXXXXXXXXXXX"string7" : "string8" XXXXXXXXXXXXXXXXXXXXXXXXXXXX...
)";
int main() {
const regex pattern{R"~("([^"]*)"\s*:\s*"([^"]*)")~"};
for (auto it = sregex_iterator(begin(text), end(text), pattern); it != sregex_iterator(); ++it) {
cout << it->format("First: $1, Second: $2") << endl;
}
}
Output:
First: string1, Second: string2
First: string3, Second: string4
First: string5, Second: string6
First: string7, Second: string8
Running (with clang and libc++): http://coliru.stacked-crooked.com/a/f0b5fd383bc227fc
This is how raw string literals look in an editor that understand them: http://bl.ocks.org/anonymous/raw/9442865/
I have a string which actually contains a number and a string, separated by ,, for instance "12,fooBar".
I would like to put it into separated variables, i.e. the number into unsigned int myNum and the string into std::string myStr.
I have the following snipped of code:
size_t pos1=value.find(',');
std::cout << value.substr(0, pos1) << " and "
<< (value.substr(0, pos1)).c_str() << std::endl;
This yields 12 and 1. Anything I missed here? What happend to the 2 in the second part?
Note: I isolated the problem to this snipped of code. I need c_str() to pass it to atoi to get the unsigend int. Here I don't want to print the second part.
Update: I actually get the string from levelDB Get. If I put a test string like I put here, it works.
The posted code produces the same substring: value.substr(0, pos1). Note that std::string::substr() does not modify the object, but returns a new std::string.
Example:
#include <iostream>
#include <string>
int main ()
{
std::string value ="12,fooBar";
unsigned int myNum;
std::string myStr;
const size_t pos1 = value.find(',');
if (std::string::npos != pos1)
{
myNum = atoi(value.substr(0, pos1).c_str());
myStr = value.substr(pos1 + 1);
}
std::cout << myNum << " and "
<< myStr << std::endl;
return 0;
}
Output:
12 and fooBar
EDIT:
If the unsigned int is the only piece required then the following will work:
unsigned int myNum = atoi(value.c_str());
as atoi() will stop at the first non-digit character (excluding optional leading - or +), in this case the ,.
The cleanest C++ style solution to this problem is to use a stringstream.
#include <sstream>
// ...
std::string value = "12,fooBar";
unsigned int myNum;
std::string myStr;
std::stringstream myStream(value);
myStream >> myNum;
myStream.ignore();
myStream >> myStr;
Your second substr should be value.substr(pos1+1,value.length())
One more option is using std::from_chars function from the 17th standard (< charconv > header):
int x;
from_chars(&s[i], &s.back(), x); // starting from character at index i parse
// the nearest interger till the second char pointer
There are different overloads for different types of value x (double etc.).