Create a new string from prefix up to character position in C++ - c++

How can I find the position of a character in a string? Ex. If I input "abc*ab" I would like to create a new string with just "abc". Can you help me with my problem?

C++ standard string provides a find method:
s.find(c)
returns the position of first instance of character c into string s or std::string::npos in case the character is not present at all. You can also pass the starting index for the search; i.e.
s.find(c, x0)
will return the first index of character c but starting the search from position x0.

std::find returns an iterator to the first element it finds that compares equal to what you're looking for (or the second argument if it doesn't find anything, in this case the end iterator.) You can construct a std::string using iterators.
#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string s = "abc*ab";
std::string s2(s.begin(), std::find(s.begin(), s.end(), '*'));
std::cout << s2;
return 0;
}

If you are working with std::string type, then it is very easy to find the position of a character, by using std::find algorithm like so:
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
int main()
{
string first_string = "abc*ab";
string truncated_string = string( first_string.cbegin(), find( first_string.cbegin(), first_string.cend(), '*' ) );
cout << truncated_string << endl;
}
Note: if your character is found multiple times in your std::string, then the find algorithm will return the position of the occurrence.

Elaborating on existing answers, you can use string.find() and string.substr():
#include <iostream>
#include <string>
int main() {
std::string s = "abc*ab";
size_t index = s.find("*");
if (index != std::string::npos) {
std::string prefix = s.substr(0, index);
std::cout << prefix << "\n"; // => abc
}
}

Related

Trouble getting two variables to update in C++ for loop

I am creating a function that splits a sentence into words, and believe the way to do this is to use str.substr, starting at str[0] and then using str.find to find the index of the first " " character. Then update the starting position parameter of str.find to start at the index of that " " character, until the end of str.length().
I am using two variables to mark the beginning position and end position of the word, and update the beginning position variable with the ending position of the last. But it is not updating as desired in the loop as I currently have it, and cannot figure out why.
#include <iostream>
#include <string>
using namespace std;
void splitInWords(string str);
int main() {
string testString("This is a test string");
splitInWords(testString);
return 0;
}
void splitInWords(string str) {
int i;
int beginWord, endWord, tempWord;
string wordDelim = " ";
string testWord;
beginWord = 0;
for (i = 0; i < str.length(); i += 1) {
endWord = str.find(wordDelim, beginWord);
testWord = str.substr(beginWord, endWord);
beginWord = endWord;
cout << testWord << " ";
}
}
It is easier to use a string stream.
#include <vector>
#include <string>
#include <sstream>
using namespace std;
vector<string> split(const string& s, char delimiter)
{
vector<string> tokens;
string token;
istringstream tokenStream(s);
while (getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
int main() {
string testString("This is a test string");
vector<string> result=split(testString,' ');
return 0;
}
You can write it using the existing C++ libraries:
#include <string>
#include <vector>
#include <iterator>
#include <sstream>
int main()
{
std::string testString("This is a test string");
std::istringstream wordStream(testString);
std::vector<std::string> result(std::istream_iterator<std::string>{wordStream},
std::istream_iterator<std::string>{});
}
Couple of issues:
The substr() method second parameter is a length (not a position).
// Here you are using `endWord` which is a poisition in the string.
// This only works when beginWord is 0
// for all other values you are providing an incorrect len.
testWord = str.substr(beginWord, endWord);
The find() method searches from the second paramer.
// If str[beginWord] contains one of the delimiter characters
// Then it will return beginWord
// i.e. you are not moving forward.
endWord = str.find(wordDelim, beginWord);
// So you end up stuck on the first space.
Assuming you got the above fixed. You would be adding space at the front of each word.
// You need to actively search and remove the spaces
// before reading the words.
nice things you could do:
Here:
void splitInWords(string str) {
You are passing the parameter by value. This means you are making a copy. A better technique would be to pass by const reference (you are not modifying the original or the copy).
void splitInWords(string const& str) {
An Alternative
You can use the stream functionality.
void split(std::istream& stream)
{
std::string word;
stream >> word; // This drops leading space.
// Then reads characters into `word`
// until a "white space" character is
// found.
// Note: it emptys words before adding any
}

How to identify string is containing only number?

How to print only text in a string? I want to print only abc from.
string numtext = "abc123";
Here is the full code:
#include <stdio.h>
int main()
{
string text = "abc123";
if (text.matches("[a-zA-Z]") //get an error initialization makes integer from pointer without a cast
{
printf("%s", text);
}
getch();
}
My string contains both numbers and letters and I want to print letters only. But I get an error. What am I doing wrong?
First of all, there is no member function called std::string::matches available in the standard string library for this case.
Secondly, The title of the question does not match the question you have asked with the code. However, I will try to deal with both. ;)
How to print only text in a string?
You could simply print each element in the string(i.e. char s) if it is an alphabet while iterating through it. The checking can be done using the standard function called std::isalpha, from the header <cctype>. (See live example here)
#include <iostream>
#include <string>
#include <cctype> // std::isalpha
int main()
{
std::string text = "abc123";
for(const char character : text)
if (std::isalpha(static_cast<unsigned char>(character)))
std::cout << character;
}
Output:
abc
How to identify string is containing only number?
Provide a function which checks for all the characters in the string whether they are digits. You can use, standard algorithm std::all_of (needs header <algorithm> to be included) along with std::isdigit (from <cctype> header) for this. (See live example online)
#include <iostream>
#include <string>
#include <algorithm> // std::all_of
#include <cctype> // std::isdigit
#include <iterator> // std::cbegin, std::cend()
bool contains_only_numbers(const std::string& str)
{
return std::all_of(std::cbegin(str), std::cend(str),
[](char charector) {return std::isdigit(static_cast<unsigned char>(charector)); });
}
int main()
{
std::string text = "abc123";
if (contains_only_numbers(text))
std::cout << "String contains only numbers\n";
else
std::cout << "String contains non-numbers as well\n";
}
Output:
String contains non-numbers as well
You could use the find_last_not_of function of std::string and the create a substr
std::string numtext = "abc123";
size_t last_character = numtext.find_last_not_of("0123456789");
std::string output = numtext.substr(0, last_character + 1);
This solution just presumes that numtext always has a pattern of text+num, means something like ab1c23 would give output = "ab".
Using C++ standard regex for such scenarios is a good idea. You can customize a lot.
Below is a simple example.
#include <iostream>
#include <regex>
int main()
{
std::regex re("[a-zA-Z]+");
std::cmatch m;//TO COLLECT THE OUTPUT
std::regex_search("abc123",m,re);
//PRINT THE RESULT
std::cout << m[0] << '\n';
}

C++ Remove punctuation from String

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

Splitting std::string and inserting into a std::set

As per request of the fantastic fellas over at the C++ chat lounge, what is a good way to break down a file (which in my case contains a string with roughly 100 lines, and about 10 words in each line) and insert all these words into a std::set?
The easiest way to construct any container from a source that holds a series of that element, is to use the constructor that takes a pair of iterators. Use istream_iterator to iterate over a stream.
#include <set>
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
using namespace std;
int main()
{
//I create an iterator that retrieves `string` objects from `cin`
auto begin = istream_iterator<string>(cin);
//I create an iterator that represents the end of a stream
auto end = istream_iterator<string>();
//and iterate over the file, and copy those elements into my `set`
set<string> myset(begin, end);
//this line copies the elements in the set to `cout`
//I have this to verify that I did it all right
copy(myset.begin(), myset.end(), ostream_iterator<string>(cout, "\n"));
return 0;
}
http://ideone.com/iz1q0
Assuming you've read your file into a string, boost::split will do the trick:
#include <set>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
std::string astring = "abc 123 abc 123\ndef 456 def 456"; // your string
std::set<std::string> tokens; // this will receive the words
boost::split(tokens, astring, boost::is_any_of("\n ")); // split on space & newline
// Print the individual words
BOOST_FOREACH(std::string token, tokens){
std::cout << "\n" << token << std::endl;
}
Lists or Vectors can be used instead of a Set if necessary.
Also note this is almost a dupe of:
Split a string in C++?
#include <set>
#include <iostream>
#include <string>
int main()
{
std::string temp, mystring;
std::set<std::string> myset;
while(std::getline(std::cin, temp))
mystring += temp + ' ';
temp = "";
for (size_t i = 0; i < mystring.length(); i++)
{
if (mystring.at(i) == ' ' || mystring.at(i) == '\n' || mystring.at(i) == '\t')
{
myset.insert(temp);
temp = "";
}
else
{
temp.push_back(mystring.at(i));
}
}
if (temp != " " || temp != "\n" || temp != "\t")
myset.insert(temp);
for (std::set<std::string>::iterator i = myset.begin(); i != myset.end(); i++)
{
std::cout << *i << std::endl;
}
return 0;
}
Let's start at the top. First off, you need a few variables to work with. temp is just a placeholder for the string while you build it from each character in the string you want to parse. mystring is the string you are looking to split up and myset is where you will be sticking the split strings.
So then we read the file (input through < piping) and insert the contents into mystring.
Now we want to iterate down the length of the string, searching for spaces, newlines, or tabs to split the string up with. If we find one of those characters, then we need to insert the string into the set, and empty our placeholder string, otherwise, we add the character to the placeholder, which will build up the string. Once we finish, we need to add the last string to the set.
Finally, we iterate down the set, and print each string, which is simply for verification, but could be useful otherwise.
Edit: A significant improvement on my code provided by Loki Astari in a comment which I thought should be integrated into the answer:
#include <set>
#include <iostream>
#include <string>
int main()
{
std::set<std::string> myset;
std::string word;
while(std::cin >> word)
{
myset.insert(std::move(word));
}
for(std::set<std::string>::const_iterator it=myset.begin(); it!=myset.end(); ++it)
std::cout << *it << '\n';
}

Parse a string to get the nth field

Im trying to parse the string located in /proc/stat in a linux filesystem using c++
I have lifted and saved the string as a variable in a c++ program
I want to lift individual values from the string. Each value is separated by a space.
I want to know how i would, for example, lift the 15th value from the string.
std::strings separated by spaces can be automatically parsed from any ostream. Simply throw the entire line into an std::istringstream and parse out the nth string.
std::string tokens;
std::istringstream ss(tokens);
std::string nth;
for (int i = 0; i < 15; ++i)
ss >> nth;
return nth;
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
// return n'th field or empty string
string Get( const std::string & s, unsigned int n ) {
istringstream is( s );
string field;
do {
if ( ! ( is >> field ) ) {
return "";
}
} while( n-- != 0 );
return field;
}
int main() {
string s = "one two three four";
cout << Get( s, 2 ) << endl;
}
I would use the split algorithm from the Boosts String Algorithms here:
#include <string>
#include <vector>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
std::string line = "...."; // parsed line
std::vector<std::string> splits;
boost::algorithm::split( splits, parsed_line, boost::is_any_of( " " ) );
std::string value;
if ( splits.size() >= 15 ) {
value = splits.at( 14 );
}
You could use boost::tokenizer with space as a separator and iterate over the values.
See this SO and that should answer most of your question.
you could use strtok function with some counter to stop when you reach nth value
You could use std::string::find to find a space and repeat until the 15th value is found.