Replace string in a vector string - c++

I want to replace a string in a vector string. I mean, I have a vector string, define vector tmpback , with info like this: name_lastname_phonenumber
I want to replace some last names. For example if someone is john_smith_5551234, I want to replace smith to smith100.
this is my code, o part of it:
vector<string> tmpback = names;
for (Int_t i = 0; i < tmpback.size(); i++) {
replace(tmpback[i].begin(),tmpback[i].end(),"smith", "smith"+number);
}
(i defined number previously as Int_t number = 0 and give some values later).
did someone have any idea of what am I doing wrong?
Thanks

std::replace does not replace sequences with other sequences. It replaces single elements with other single elements. Besides that, your method of appending a number to a string does not work.
Try boost::replace_first or boost::replace_all along with either boost::lexical_cast or std::to_string(c++11 only) for converting a number to a string.
using namespace boost;
std::string replace_str = std::string("smith") + lexical_cast<std::string>(number);
replace_first(tmpback[i], "smith", replace_str);
You could also search for the sub-string, and if you find it, insert the number (converted to a string) after it:
std::string::size_type pos = tmpback[i].find("smith");
if (pos != std::string::npos)
{
// adding 5 because that's the length of "smith"
tmpback[i].insert(pos + 5, std::to_string(number));
}

My immediate reaction would be to wonder why you're putting yourself in this situation at all. Instead of jamming three separate items into a string, then manipulating pieces of that string, why not create a struct so you can work with each piece separately?
struct person {
std::string first_name;
std::string last_name;
int record_no;
std::string phone_number;
};
This way, instead of tacking the record number (or whatever exactly your '100' represents) onto the end of the last name, you just give it its own field, and write an appropriate number as needed:
vector<person> tmpback;
for (int i=0; i<tmpback.size(); i++)
tmpback[i].record_no = number;

Related

Suggestions that could improve my string splitting function

I'm new to C++ and I'm trying to write some basic functions to get the hang of some of it, I decided on making a custom function to split up a string into tokens every time a specific delimiter is reached.
I've made it work successfully, but since I'm new, I'd like to hear from more experienced programmers on if there is a better way to go about it. This is my code:
vector<string> split(string const str, string const separator=" ") {
int str_len = str.length();
int sep_len = separator.length();
int current_index {0};
vector<string> strings {};
for(int i {0}; i < str_len; ++i) {
if(str.substr(i, sep_len) == separator) {
strings.push_back(str.substr(current_index, i-current_index));
current_index = i + sep_len;
}
}
strings.push_back(str.substr(current_index, str_len-current_index));
return strings;
}
One thing I will say is, I don't like how I had to put
strings.push_back(str.substr(current_index, str_len-current_index));
this after the entire iteration to get the final part of the string. I just can't think of any different methods.
Use std::string::find() to find separators in the string, which is probably much more efficient than your loop that checks for each possible position if the substring at that position matches the separator. Once you have that, you can make use of the fact that if the separator is not found, find() returns std::string::npos, which is the largest possible value of std::string::size_type, so just pass this to substr() to get everything from the current position to the end of the string. This way you can avoid the second push_back().
vector<string> split(string const &str, string const &separator=" ") {
string::size_type current_index {};
vector<string> strings;
while (true) {
auto separator_index = str.find(separator, current_index);
strings.push_back(str.substr(current_index, separator_index - current_index));
if (separator_index == str.npos)
break;
else
current_index = separator_index + separator.size();
}
return strings;
}
Note: ensure you pass the input parameters by reference to avoid unnecessary copies being made.

Output partial string of a certain index of an array

C++ newbie here, I'm not sure if my title describes what I am trying to do perfectly, but basically I am trying to output one line of a string array for a certain index of that array.
For example: Say myArray[2] is the 3rd index of a string array, and it holds an entire paragraph, with each sentence separated by a newline character.
contents of myArray[2]: "This is just an example.
This is the 2nd sentence in the paragraph.
This is the 3rd sentence in the paragraph."
I would like to output only the first sentence of the content held in the 3rd index of the string array.
Desired output: This is just an example.
So far I have only been able to output the entire paragraph instead of one sentence, using the basic:
cout << myArray[2] << endl;
But obviously this is not correct. I am assuming the best way to do this is to use the newline character in some way, but I am not sure how to go about that. I was thinking I could maybe copy the array into a new, temporary array which would hold in each index a sentence of the paragraph held in the original array index, but this seems like I am complicating the issue too much.
I have also tried to copy the string array into a vector, but that didn't seem to help my confusion.
You can do something along these lines
size_t end1stSentencePos = myArray[2].find('\n');
std::string firstSentence = end1stSentencePos != std::string::npos?
myArray[2].substr(0,end1stSentencePos) :
myArray[2];
cout << firstSentence << endl;
Here's the reference documentation of std::string::find() and std::string::substr().
Below is a general solution to your problem.
std::string findSentence(
unsigned const stringIndex,
unsigned const sentenceIndex,
std::vector<std::string> const& stringArray,
char const delimiter = '\n')
{
auto result = std::string{ "" };
// If the string index is valid
if(stringIndex < stringArray.size())
{
auto index = unsigned{ 0 };
auto posStart = std::string::size_type{ 0 };
auto posEnd = stringArray[stringIndex].find(delimiter);
// Attempt to find the specified sentence
while((posEnd != std::string::npos) && (index < sentenceIndex))
{
posStart = posEnd + 1;
posEnd = stringArray[stringIndex].find(delimiter, posStart);
index++;
}
// If the sentence was found, retrieve the substring.
if(index == sentenceIndex)
{
result = stringArray[stringIndex].substr(posStart, (posEnd - posStart));
}
}
return result;
}
Where,
stringIndex is the index of the string to search.
sentenceIndex is the index of the sentence to retrieve.
stringArray is your array (I used a vector) that contains all of the strings.
delimiter is the character that specifies the end of a sentence (\n by default).
It is safe in that if an invalid string or sentence index is specified, it returns an empty string.
See a full example here.

Erase words from a string (in C++)

I want to delete some words from a string but my code doesn't work . I don't have any errors or warnings , but I'm thinking that my string becomes empty. Could someone help me with this? I tried to convert my initial strings into 2 vectors, so that I can navigate more easily then
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string s("Somewhere down the road");
string t("down");
istringstream iss(s);
vector <string> plm;
vector <string> plm2;
do
{
string sub;
iss >> sub;
plm.push_back(sub);
} while (iss);
for(unsigned int i=0 ; i<plm.size();i++){
cout<<plm[i];}
istringstream ist(t);
do
{
string subb;
ist >> subb;
plm2.push_back(subb);
} while (ist);
for(int i=0;i<plm.size();i++){
for(int j=0;j<plm2.size();i++){
{if (plm[i]==plm2[j])
plm.erase(plm.begin()+j);}}}
for(int i=0 ; i<plm.size();i++)
cout<<plm[i];
}
Warning: this is really just a comment that's too long to fit in a comment field. Oh, and a bit of a rant at that.
I'm sure glad we have these modern languages to make life so much easier than it was decades ago. Consider, for example, what this job looked like an the long-since moribund SNOBOL 4 programming language:
s = 'somewhere down the road'
del s 'down' = :s(del)
OUTPUT = s
God, it's nice that we've since made so much progress that we don't have to deal with 3 whole lines of code, and we can now do the job with only 52 lines instead (oh, except that the 52 lines don't actually work, but let's ignore that for the moment).
I guess, in fairness, we can do the job a little more compactly in C++ though. One obvious way would be with std::remove_copy, some stream iterators, and a stringstream or two:
std::istringstream input("somewhere down the road");
std::string del_str("down");
std::istream_iterator<std::string> in(input), end;
std::ostringstream result;
std::remove_copy(in, end, std::ostream_iterator<std::string>(result, " "), del_str);
std::cout << result.str();
There is no benefit in converting to vector - string itself already provides all that is necessary for what you want to do. Anyway, do it this way:
vector<char> v;
v.assign(s.c_str(), s.c_str() + s.length()); // without...
v.assign(s.c_str(), s.c_str() + s.length() + ); // including...
// ... terminating null character
Now it gets easy:
size_t pos = s.find(t);
if(pos != string::npos)
{
s.erase(pos, t.length());
}
This does not care, however, about leaving multiple whitespace or if t is not an entire word within s (e. g. t = "down"; s = "I'm going to downtown."; would result in s == "I'm going to town."), but you did not do so either...
First problem is, if std::string::erase is called only with the beginning position, it erases everything until the end of string.
Second problem is, that the code will just erase all letters which are in the second string, one by one. I.e. not the entire word - for that, you would need to check if the entire word matches, and only then erase (the entire length of the word). Ask yourself - what will happen in the code, if e.g. the first two letters will match, but not the rest of the word?
In your second for loop you never incremented j and inside the if (plm[i]==plm2[j]) block you used j instead of i as your offset in erase().
for(int i=0;i<plm.size();i++)
{
for(int j=0;j<plm2.size();j++)//here you need to increment j
{
if (plm[i]==plm2[j])
plm.erase(plm.begin()+i);//here the offset should be i
}
}
Another thing don't use a do...while loop to read from the stringstream and push back on the vector. If the reading fails you will be pushing invalid data to the vector, instead try something like:
string sub;
while(iss >> sub;)
plm.push_back(sub);//only if reading is successful
...//do the same for the other istringstream too
You do not increment j this is the first thing I saw on your code. Write it correctly then if it still doesnt work, then ask!

Quick way to split string at first sign of a digit

I have a list of data I need to parse that contains a name and phone number in a text file. The name and phone number must be split into different string vars, but I can't really think of a fast method to do so. I can easily run a for loop and do something like
//file line read into string `line`
string name;
string number;
for(int i = 0; i < line.length(); i++) {
if(isDigit(line[i])) {
name = line.substr(0, i-1);
number = line.substr(i, line.length()-i);
}
}
but I feel there has to be an easy way to do this in C++.
You could use find_first_of to find the first digit without using a loop:
string s("hello12345");
size_t i = s.find_first_of("0123456789");
string name(s.substr(0, i));
string number(s.substr(i));
Demo.
Note that if you wish to take a substring to the end of the original string, you do not need to pass the length: the library will figure it out automatically for you.

Manipulating specific position in string according to one another

I have a string which has different city names. The format like this :
string cities = "-Paris-Berlin-Cologne-"
And also there is another string which contains some voting results for these cities.
string vote = "-31.2-42.5-40-"
I need to define a function which takes input from user for ex : Berlin
Then function will find and change the result of vote in "string vote"
I tried with counting "-" separators but I couldn't succeed.
Any help would appreciate.
Thank you.
Split both strings at the separators and put the results in a map
std::vector<std::string> split(std::string const& s, std::string const& sep);
std::vector<std::string> const c = split(cities, "-");
std::vector<std::string> const v = split(votes, "-");
// now put them all in a map
assert(c.size() == v.size());
std::map<std::string, float> city2vote;
for (std::vector<std::string>::size_type i=0; i != c.size(); ++i)
{
city2vote[c[i]] = atof(v[i]);
}
// update vote for Berlin
city2vote["Berlin"] = 42.0;
The split function is strait forward, but Boost also provides an implementation if you can use libraries. I used atof for simplicity. In real life, a stringstream would be a much better choice.
Would using a regex search to find the positions in the string of the hyphens, then changing the values between those positions accordingly be an acceptable solution?
Edit - On second thoughts, you needn't overcomplicate things by using regex, you could just use a for loop to scan through the string
First I think you should map each delimited string from cities to vote. You can do it like this:
std::map<std::string, std:string> city_to_vote;
std::istringstream i1(cities), i2(vote);
for (std::string str1, str2; std::getline(i1, str1, '-') &&
std::getline(i2, str2, '-'); )
{
if (!str1.empty() && !str2.empty())
{
city_to_vote.emplace(std::make_pair(str1, str2));
}
}
Then once you receive string input from the user, check if it is inside the map, access the value that it is mapped to, and use a replace algorithm to augment the vote string.