need help on splitting a string in c++ [duplicate] - c++

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
i need a suggestion on how to take one string of text and split it up based on a certain character, in this case "," without the use of any outside libraries
the lines of text are:
Amadeus,Drama,160 Mins.,1984,14.83
As Good As It Gets,Drama,139 Mins.,1998,11.3
Batman,Action,126 Mins.,1989,10.15
Billy Elliot,Drama,111 Mins.,2001,10.23
BR,SF,117,1982,11.98
Shadowlands,Drama,133 Mins.,1993,9.89
Shrek,Animation,93 Mins,2001,15.99
Snatch,Action,103 Mins,2001,20.67
The Lord of the Rings,Fantasy,178 Mins,2001,25.87

If you don't want to resort to other libraries (Boost.Tokenizer is a good choice IMO), here is some simple code for doing that:
#include <string>
#include <vector>
using namespace std;
vector<string> tokenize(string const& s, string const& separator)
{
size_t start = 0;
size_t pos = s.find(separator);
vector<string> v;
while (pos != string::npos)
{
string sub = s.substr(start, pos - start);
v.push_back(sub);
start = pos + 1;
pos = s.find(separator, start);
}
string sub = s.substr(start, pos - start);
v.push_back(sub);
return v;
}
int main()
{
string s = "asfa,adf,daf,c";
vector<string> v = tokenize(s, ",");
// Do what you want with v...
return 0;
}

You could just find the indices of the commas and store them in a vector, then use string::substr (http://www.cplusplus.com/reference/string/string/substr/) to get the substrings between those indices.

Related

Is there any way I could further optimize this program? [duplicate]

This question already has answers here:
read words from line in C++
(2 answers)
Right way to split an std::string into a vector<string>
(12 answers)
Closed 12 days ago.
I've been trying to learn how to optimize C++ in the context of low latency trading systems, and am wondering if this implementation could be improved. I would appreciate any insight, either specific or general.
// Code to add each word in string to vector
int main() {
std::string originalText = "Hello World!";
std::vector<std::string> words;
words.reserve(originalText.length()); // unsure if this could be more accurate
std::size_t wStart = 0;
std::size_t pos = originalText.find(" ");
while(pos != std::string::npos) {
words.emplace_back(&originalText[wStart], pos - wStart);
wStart = pos + 1;
pos = originalText.find(" ", wStart);
}
words.emplace_back(&originalText[wStart], originalText.size() - wStart);
return 0;
}
You still allocate and copy std::strings from the input that's not needed. You can use string_views. This is no way near optimized for a trading system though.
I still use a vector and the will reallocate while it grows.
When optimizing code there is two things, keep thinking/researching if there is another algorithm (that usually brings the biggest performance gain). Then keep profiling to find your (real) bottlenecks.
Anyway here is a split function that can split without making string copies and can split on multiple characters (you can still optimize that to only split on spaces if that is the only delimiter)
std::vector<std::string_view> split_string(std::string_view string, std::string_view delimiters)
{
std::vector<std::string_view> substrings;
if(delimiters.size() == 0ul)
{
substrings.emplace_back(string);
return substrings;
}
auto start_pos = string.find_first_not_of(delimiters);
auto end_pos = start_pos;
auto max_length = string.length();
while(start_pos < max_length)
{
end_pos = std::min(max_length, string.find_first_of(delimiters, start_pos));
if(end_pos != start_pos)
{
substrings.emplace_back(&string[start_pos], end_pos - start_pos);
start_pos = string.find_first_not_of(delimiters, end_pos);
}
}
return substrings;
}

how do you split a string embedded in a delimiter in C++?

I understand how to split a string by a string by a delimiter in C++, but how do you split a string embedded in a delimiter, e.g. try and split ”~!hello~! random junk... ~!world~!” by the string ”~!” into an array of [“hello”, “ random junk...”, “world”]? are there any C++ standard library functions for this or if not any algorithm which could achieve this?
#include <iostream>
#include <vector>
using namespace std;
vector<string> split(string s,string delimiter){
vector<string> res;
s+=delimiter; //adding delimiter at end of string
string word;
int pos = s.find(delimiter);
while (pos != string::npos) {
word = s.substr(0, pos); // The Word that comes before the delimiter
res.push_back(word); // Push the Word to our Final vector
s.erase(0, pos + delimiter.length()); // Delete the Delimiter and repeat till end of String to find all words
pos = s.find(delimiter); // Update pos to hold position of next Delimiter in our String
}
res.push_back(s); //push the last word that comes after the delimiter
return res;
}
int main() {
string s="~!hello~!random junk... ~!world~!";
vector<string>words = split(s,"~!");
int n=words.size();
for(int i=0;i<n;i++)
std::cout<<words[i]<<std::endl;
return 0;
}
The above program will find all the words that occur before, in between and after the delimiter that you specify. With minor changes to the function, you can make the function suit your need ( like for example if you don't need to find the word that occurs before the first delimiter or last delimiter) .
But for your need, the given function does the word splitting in the right way according to the delimiter you provide.
I hope this solves your question !

Is there a way to erase two given values with loop?

How do I erase if string sdl1 holds two values like "37". Considering that are two different values 3 and 7. Do I need some sort of list or only loop? Thank you
#include <iostream>
#include <string>
#include <algorithm>
#include <functional>
#include <vector>
#include <conio.h>
#include <sstream>
#include <stdio.h>
#include <iterator>
using namespace std;
void eraseAllSubStr(std::string & mainStr, const std::string & toErase)
{
size_t pos = std::string::npos;
while ((pos = mainStr.find(toErase)) != std::string::npos)
{
mainStr.erase(pos, toErase.length());
}
}
int main()
{
std::string str = "123456789";
//Let's Say I want to delete 5 and 8 and string sdl1 = "58".
string sdl1 = "5";
eraseAllSubStr(str, sdl1);
std::cout << str << std::endl;
return 0;
}
The output of the minimal reprod. example:
12346789
5 was erased.
But I would like to erase two values like 5 and 8 where string sdl1 = "58"
If I understand your actual question:
"What If I want to remove "58" like 5 and 8?"
and you want to provide std::string sdl1 = "58"; and have both 5 and 8 removed from std::string str = "123456789"; in a single loop, then you can simply use std::basic_string::find_first_of to locate the position of either 5 or 8 and then use std::basic_string::erase to remove the character. The only constraint is you only want to attempt the removal of characters while str.find_first_of (sdl1) != std::basic::npos).
A for loop is tailor made for the implementation, e.g.:
std::string str = "123456789";
//Let's Say I want to delete 5 and 8 and string sdl1 = "58".
std::string sdl1 = "58";
for (size_t pos = str.find_first_of (sdl1);
pos != std::string::npos;
pos = str.find_first_of (sdl1))
str.erase (pos, 1);
Putting it altogether in a short example, you could do:
#include <iostream>
#include <string>
int main (void) {
std::string str = "123456789";
//Let's Say I want to delete 5 and 8 and string sdl1 = "58".
std::string sdl1 = "58";
for (size_t pos = str.find_first_of (sdl1);
pos != std::string::npos;
pos = str.find_first_of (sdl1))
str.erase (pos, 1);
std::cout << "str: " << str << '\n';
}
Example Use/Output
$ ./bin/erasechars
str: 1234679
Erase as substring
If you want to erase as a substring, the code you wrote is solution to your problem. Run again your code by putting
std::string str = "123456789";
string sdl1 = "56";
You will get your ouput 1234789.
Once again set the inputs
std::string str = "12345678956123";
string sdl1 = "56";
You will get your output 1234789123
So you've successfully removed all the occurrences of 56 from your main string str.
The way std::string::find() works, it searches the string for the first occurrence of the sequence specified by its arguments. So it will work same for a substring as it works for a single character.
Similarly std::string::erase() erases a part of the string, reducing its length. All you need is to specify the starting index and the length of the substring (i.e. string ::erase (size_type idx, size_type len )) you would like to remove.
So, your code will work for removing all the occurrences of a given substring.
Erase as character
If you want to remove one or more characters from a string like you mentioned 5 and 8. You can use your code with simple modification to your eraseAllSubStr function.
void eraseAllSubStr(std::string & mainStr, const std::string & toErase)
{
size_t pos = std::string::npos;
// erase all the occurrences of the characters that are
// given through toErase string
// and obviously the length of a char is 1
for( int id = 0; id < toErase.size(); id++)
{
while ((pos = mainStr.find(toErase[id])) != std::string::npos)
{
mainStr.erase(pos,1);
}
}
}

To replace one char by a higher amount of chars within a string, without deleting other letters in C++ [duplicate]

This question already has answers here:
Replace char in string with some string inplace
(4 answers)
Closed 4 years ago.
I want to replace character 'ü' in a string if found in it. My code replaces ü, but also deleting other letters in the string.
if (word.find('ü') != string::npos)
{
word.replace(word.find('ü'), 'ü', "ue");
}
Not a one-liner, but erase followed by insert is clear enough.
size_t x = word.find('ü');
while (x != string::npos)
{
word.erase(x, 1);
word.insert(x, "ue");
x = word.find('ü');
}
You can find the position of ü, starting from index 0 until end of the string and whenever you find, replace it with ue using the information of both position where you found and the length of the string you would like to find in the given string.
Something like follows: SEE LIVE HERE
#include <iostream>
#include <string>
#include <algorithm>
#include <cstddef>
int main()
{
std::string word("Herr Müller ist ein König.");
std::string findThis = "ü";
std::string replaceWith = "ue";
std::size_t pos = 0;
while ((pos = word.find(findThis, pos)) != std::string::npos)
{
word.replace(pos, findThis.length(), replaceWith);
pos += replaceWith.length();
}
std::cout << word << std::endl;
return 0;
}
Output:
Herr Mueller ist ein König.
If using boost is an option you can do something like this
#include <boost/algorithm/string.hpp>
int main()
{
std::string str("Herr Müller ist ein König.");
boost::replace_all(str, "ü", "ue");
std::cout << str << std::endl;
return 0
}

C++ Breaking up a string using multiple delimiters [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Split a string into words by multiple delimiters in C++
I'm currently trying to read a file where each line has a variation of tabs and spaces separating key attributes that need to be inserted into a binary tree.
My question is: How do I split a line up using multiple delimiters using only the STL? I've been trying to wrap my head around this for the good part of the day to no avail.
Any advice would be very much appreciated.
Use std::string::find_first_of
vector<string> bits;
size_t pos = 0;
size_t newpos;
while(pos != string::npos) {
newpos = str.find_first_of(" \t", pos);
bits.push_back(str.substr(pos, newpos-pos));
if(pos != string::npos)
pos++;
}
Using string::find_first_of() [1]:
int main ()
{
string str("Replace the vowels in this sentence by asterisks.");
size_t found;
found = str.find_first_of("aeiou");
while (found != string::npos) {
str[found]='*';
found=str.find_first_of("aeiou", found + 1);
}
cout << str << endl;
return 0;
}