Concatenate one character from string 1 and second character from string 2 - c++

I want to concatenate two strings but it like odd position characters from strin1 and even position characters from stri2.
This is what i have done:
string mainvalue(string og2,string eg2)
{
string odd=og2;
string even=eg2;
string s3;
reverse(odd.begin(),odd.end());
cout<<"Main ordered text is :"<<odd<<endl;
int length1=odd.length();
int length2=even.length();
for(int i=0;i<length1;i++)
{
for(int j=0;j<length2;j++)
{
s3 += odd[j]+even[j];
}
}
cout<<"Complete text is :"<<s3<<endl;
//return s3;
}
Output is look like : :▌π═▌π═▌π═

The reason for your strange output is that you're adding two characters, and adding two alphabetical characters rarely gives a printable result.
But your code would be incorrect even if you could add characters to make strings, as your result would basically be length1 copies of the desired result.
Assuming that the input strings are of equal length, one simple solution is to alternately take one character from each string.
This assumes that the first element is "odd" - if it's "even", just swap the two lines in the loop:
string mainvalue(string odds, string evens)
{
string merged;
for (string::size_type i = 0; i < odds.size(); ++i)
{
merged += odds[i];
merged += evens[i];
}
return merged;
}
You could also do something like this:
string mainvalue(string odds, string evens)
{
auto merged = string {odds.size() + evens.size(), ' '};
auto odd = odds.begin();
auto even = evens.begin();
auto out = merged.begin();
while (odd != odds.end())
{
*out++ = *odd++;
*out++ = *even++;
}
return merged;
}

Related

Cannot properly eliminate string one from another character by character

Here the function (sub) takes two string as input, traversing two string I try to find out if there is any matches in string1 compared to string2. If any that character of string1 is replaced by NULL character. Now this works properly for non repeated character. But if string1 has more than one character that matches once it all replaced by NULL character where i needed only one replacement. For example if string1 and string2 are 122 and 2, after elimination i need 1 2 where i gets now a single 1.
void sub (string str1, string str2){
int i,j,k;
for(i=0; i<=str2.size() ; i++){
for(j=0; j<=str1.size() ; j++ ){
if( str2[i] == str1[j] )
str1[j] = NULL;
}
}
cout<<str1;
expected result is 1 2 instead of 1, if str1=122 and str2=2
You are making things more difficult on yourself than they need to be. The string library provides two functions that can do exactly what you need in a single call.
The member function std::basic_string::find_first_of will locate the first occurrence of a character from string2 in string1 returning the position where it is found.
The std::basic_string::erase function can remove all characters from string1 beginning at that position.
Your sub function will then reduce to:
void sub (std::string& s1, const std::string& s2)
{
s1.erase (s1.find_first_of (s2));
}
A short example using your given strings would be:
#include <iostream>
#include <string>
void sub (std::string& s1, const std::string& s2)
{
s1.erase (s1.find_first_of (s2));
}
int main (void) {
std::string s1 ("122"), s2 ("2");
sub (s1, s2);
std::cout << "s1: " << s1 << "\ns2: " << s2 << '\n';
}
Example Use/Output
$ ./bin/sub1at2
s1: 1
s2: 2
Look things over and let me know if you have further questions.
You can't remove a character from a string by setting it to NULL. The length of the string will remain the same. But one way to simulate the removal of the duplicates is to return a new string that matches the return conditions.
First iterate over the second string and use a hash table to map each character in s2 to true. Then iterate over s1 and add the current character to a new string only if the character in the hash table maps to false. Remapping the character to false after this condition ensures that all but one of the number of characters is written to the result string.
string remove_first_duplicates(string s1, string s2) {
unordered_map<char, bool> m;
string result;
for (char i : s2) m[i] = true;
for (char i : s1) {
if (!m[i]) result += i;
m[i] = false;
}
return result;
}
NULL is not a character-constant, even if \0 is the null character. It's a macro for a null pointer constant, and for historical reasons is often defined as 0, though it might be nullptr or any other null pointer constant.
Zeroing out characters does not stop them being part of the string. for that, you must move the remaining ones and adjust the length.
If you only want to do it once, on the first match, leve the function with return afterwards.
Consider separating it into two functions: One for finding a match, and one calling that and using the result for removing the first match.
As far as I understood your question, you want to remove one char from str1 corresponding to a match in str2.
void sub(string str1, string str2)
{
int i = 0, j = 0;
while (j < str2.size())
{
if (str1[i] == str2[j])
{
str1[i] = NULL; // could use str1.erase(i,1)
i = 0;
j += 1;
continue;
}
else
i += 1;
if (i == str1.size() - 1)
{
i = 0;
j += 1;
}
}
cout<<str1<<endl;
}
This will yield the output you desire. But this will produce NULL char in str1, better option is to use erase functionality from std::string.

How to find see if one string is located inside of another and replace it?

I need help with the following program. I don't know how to check if occurrences of string2 are inside string1, and then replace them with string3.
Write a function named replaceSubstring. The function should accept three string object arguments. Let’s call them string1, string2, and string3. It should search string1 for all occurrences of string2. When it finds an occurrence of string2, it should replace it with string3. Demonstrate and test the function with a complete program.
For example, suppose the three arguments have the following values:
string1: "the dog jumped over the fence"
string2: "the"
string3: "that"
With these three arguments, the function would return a string object with the value "that dog jumped over that fence". Demonstrate the function in a complete program.
int main()
{
string string1 = "xyzxyzxyz";
string string2 = "xyz";
string string3 = "a";
replaceSubstring(string1, string2, string3);
return 0;
}
void replaceSubstring(string string1, string string2, string string3)
{
string result;
for (int i = 0; i < string1.length(); i++){
if (string1.find(string2, i)){
result = string1.replace(i, string3.length()+i, string3);
}
}
cout << result;
}
A quick way to do this is with the Boost String Algorithms Library as stated here
#include <boost/algorithm/string/replace.hpp>
{ // 1.
string test = "abc def abc def";
boost::replace_all(test, "abc", "hij");
boost::replace_all(test, "def", "klm");
}
{ // 2.
string test = boost::replace_all_copy
( boost::replace_all_copy<string>("abc def abc def", "abc", "hij")
, "def"
, "klm"
);
}
Because, as stated here:
There is no one built-in function in C++ to do this. If you'd like to replace all instances of one substring with another, you can do so by intermixing calls to string::find and string::replace. For example:
size_t index = 0;
while (true) {
/* Locate the substring to replace. */
index = str.find("abc", index);
if (index == std::string::npos) break;
/* Make the replacement. */
str.replace(index, 3, "def");
/* Advance index forward so the next iteration doesn't pick it up as well. */
index += 3;
}
If the objective is to implement your own code for replacing matched strings, I would recommend that you read up on Z and KMP algorithms. For a quick and dirty solution, see below Geeks For Geeks:
// C program for Naive Pattern Searching algorithm
#include<stdio.h>
#include<string.h>
void search(char *pat, char *txt)
{
int M = strlen(pat);
int N = strlen(txt);
/* A loop to slide pat[] one by one */
for (int i = 0; i <= N - M; i++)
{
int j;
/* For current index i, check for pattern match */
for (j = 0; j < M; j++)
if (txt[i+j] != pat[j])
break;
if (j == M) // if pat[0...M-1] = txt[i, i+1, ...i+M-1]
printf("Pattern found at index %d \n", i);
}
}
/* Driver program to test above function */
int main()
{
char txt[] = "AABAACAADAABAAABAA";
char pat[] = "AABA";
search(pat, txt);
return 0;
}
After the positions have been found, write a method to build a new string and replace, add, delete characters, one by one starting at the positions.
string.find returns the index of the first character of the found string. Here's a small example.
int main()
{
string myString = "ThisMessageIsPointLess";
string strToFind = "Is";
size_t idx = myString.find(strToFind.c_str());
// idx = 11 because 'Is' starts at the 11th position in the string
idx = myString.find("Foo");
// idx == std::string::npos because it hasn't found "Foo" in myString
In all cases, you should check that the substring has been found in the string. You just have to compare the index that's being returned with the default failure value from the library:
if (idx == std::string::npos)
{
// Failed to find the substring
return false;
}
Now, there are quite a few overloads of std::string::replace and they can do different things. I suggest you use the one that takes two iterators and the 'replacement' string.
string replacement = "Seems";
myString.replace(myString.begin() + idx, myString.begin() + idx + strToFind.size(), replacement.c_str());
// myString = "ThisMessageSeemsPointless"
return true;
The overload we've used takes the iterator of the first character to replace, the iterator of the last character to replace, and the replacement string. We know that the string starts at idx from the beginning. By simple logic, we know it should end at idx + strToFind.size() from the beginning.
PS: it might be relevant to name your variables so other people understand them more easily. Don't put "string" in the name; its type is string so that's redundant. Consider replacing string2 by token and string3 by newToken or replacement... anything that's more meaningful than numbers.
Last thing, you might want to pass your variables by reference (for string1) and by const-reference (for string2 and string3). This will avoid creating local copies of the strings and should improve overall performance.
bool replaceSubstring(string& string1, string const& string2, string const& string3)
Your function has several problems in it:
you did not follow the instructions! "the function would return a string object...". your function does not return anything. It just outputs the result to the console screen instead. That should be main()'s responsibility instead.
you have the right idea to use std::string::find() and std::replace(), but you are using them both completely wrong.
find() returns the index of the substring, or -1 (well, technically std::string::npos) if not found. Any value other than 0 will evaluate as true in an if expression. Your code is assuming that the substring is found at the same index that you are passing into find() as an input parameter, and that is simply not guaranteed.
the version of replace() you are calling expects a starting index and the number of characters to replace. You are not passing it the index returned by find(), and you are passing it the wrong character count, too.
You are also looping through the input string one character at a time. Replacing substrings within the same input string that you are looping through is going to reek havoc with your looping logic.
With that said, try this instead:
string replaceSubstring(const string &string1, const string &string2, const string &string3)
{
string result = string1;
string::size_type pos = 0;
do
{
pos = result.find(string2, pos);
if (pos == string::npos) break;
result.replace(pos, string2.length(), string3);
pos += string3.length();
}
while (true);
return result;
}
int main()
{
string string1 = "the dog jumped over the fence";
string string2 = "the";
string string3 = "that";
string result = replaceSubstring(string1, string2, string3);
cout << result;
return 0;
}
Without any additional library like boost, you need to write a custom replacement algorithm using the std library. This one computes the resulting string as a returned value.
string replaceSubstring(const string& string1, const string& string2, const string& string3)
{
string result;
size_t posStart = 0, posFound;
for(; (posFound = string1.find(string2, posStart)) != string1.npos;
posStart = posFound + string2.size())
{
copy(string1.begin()+posStart, string1.begin()+posFound, back_inserter(result));
result.append(string3);
}
copy(string1.begin()+posStart, string1.end(), back_inserter(result));
return result;
}
Of course you can easily change it into void by changing the fisrt parameter from const string& string1 to string& string1 and assigning it from the result before returning.
If this code is to run on large strings and if it turns out that the allocations needed by the back-insertion are not correctly optimized by the implementation (a concern raised by #RemyLebeau in the comments), you can make some reservation prior to the copy statements:
...
result.reserve(result.size() + posFound + string3.size() + 2 - posStart);
copy(string1.begin()+posStart, string1.begin() + posFound, back_inserter(result));
...
result.reserve(result.size() + string1.size() + 2 - posStart);
copy(string1.begin()+posStart, string1.end(), back_inserter(result));

Split string path with space

I am writing a program that should receive 3 parameters by User: file_upload "local_path" "remote_path"
code example:
std::vector split(std::string str, char delimiter) {
std::vector<string> v;
std::stringstream src(str);
std::string buf;
while(getline(src, buf, delimiter)) {
v.push_back(buf);
}
return v;
}
void function() {
std::string input
getline(std::cin, input);
// user input like this: file_upload /home/Space Dir/file c:\dir\file
std::vector<std::string> v_input = split(input, ' ');
// the code will do something like this
if(v_input[0].compare("file_upload") == 0) {
FILE *file;
file = fopen(v_input[1].c_str(), "rb");
send_upload_dir(v_input[2].c_str());
// bla bla bla
}
}
My question is: the second and third parameter are directories, then they can contain spaces in name. How can i make the split function does not change the spaces of the second and third parameter?
I thought to put quotes in directories and make a function to recognize, but not work 100% because the program has other functions that take only 2 parameters not three. can anyone help?
EDIT: /home/user/Space Dir/file.out <-- path with space name.
If this happens the vector size is greater than expected, and the path to the directory will be broken.. this can not happen..
the vector will contain something like this:
vector[1] = /home/user/Space
vector[2] = Dir/file.out
and what I want is this:
vector[1] = /home/user/Space Dir/file.out
Since you need to accept three values from a single string input, this is a problem of encoding.
Encoding is sometimes done by imposing fixed-width requirements on some or all fields, but that's clearly not appropriate here, since we need to support variable-width file system paths, and the first value (which appears to be some kind of mode specifier) may be variable-width as well. So that's out.
This leaves 4 possible solutions for variable-width encoding:
1: Unambiguous delimiter.
If you can select a separator character that is guaranteed never to show up in the delimited values, then you can split on that. For example, if NUL is guaranteed never to be part of the mode value or the path values, then we can do this:
std::vector<std::string> v_input = split(input,'\0');
Or maybe the pipe character:
std::vector<std::string> v_input = split(input,'|');
Hence the input would have to be given like this (for the pipe character):
file_upload|/home/user/Space Dir/file.out|/home/user/Other Dir/blah
2: Escaping.
You can write the code to iterate through the input line and properly split it on unescaped instances of the separator character. Escaped instances will not be considered separators. You can parameterize the escape character. For example:
std::vector<std::string> escapedSplit(std::string str, char delimiter, char escaper ) {
std::vector<std::string> res;
std::string cur;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == delimiter) {
res.push_back(cur);
cur.clear();
} else if (str[i] == escaper) {
++i;
if (i == str.size()) break;
cur.push_back(str[i]);
} else {
cur.push_back(str[i]);
} // end if
} // end for
if (!cur.empty()) res.push_back(cur);
return res;
} // end escapedSplit()
std::vector<std::string> v_input = escapedSplit(input,' ','\\');
With input as:
file_upload /home/user/Space\ Dir/file.out /home/user/Other\ Dir/blah
3: Quoting.
You can write the code to iterate through the input line and properly split it on unquoted instances of the separator character. Quoted instances will not be considered separators. You can parameterize the quote character.
A complication of this approach is that it is not possible to include the quote character itself inside a quoted extent unless you introduce an escaping mechanism, similar to solution #2. A common strategy is to allow repetition of the quote character to escape it. For example:
std::vector<std::string> quotedSplit(std::string str, char delimiter, char quoter ) {
std::vector<std::string> res;
std::string cur;
for (size_t i = 0; i < str.size(); ++i) {
if (str[i] == delimiter) {
res.push_back(cur);
cur.clear();
} else if (str[i] == quoter) {
++i;
for (; i < str.size(); ++i) {
if (str[i] == quoter) {
if (i+1 == str.size() || str[i+1] != quoter) break;
++i;
cur.push_back(quoter);
} else {
cur.push_back(str[i]);
} // end if
} // end for
} else {
cur.push_back(str[i]);
} // end if
} // end for
if (!cur.empty()) res.push_back(cur);
return res;
} // end quotedSplit()
std::vector<std::string> v_input = quotedSplit(input,' ','"');
With input as:
file_upload "/home/user/Space Dir/file.out" "/home/user/Other Dir/blah"
Or even just:
file_upload /home/user/Space" "Dir/file.out /home/user/Other" "Dir/blah
4: Length-value.
Finally, you can write the code to take a length before each value, and only grab that many characters. We could require a fixed-width length specifier, or skip a delimiting character following the length specifier. For example (note: light on error checking):
std::vector<std::string> lengthedSplit(std::string str) {
std::vector<std::string> res;
size_t i = 0;
while (i < str.size()) {
size_t len = std::atoi(str.c_str());
if (len == 0) break;
i += (size_t)std::log10(len)+2; // +1 to get base-10 digit count, +1 to skip delim
res.push_back(str.substr(i,len));
i += len;
} // end while
return res;
} // end lengthedSplit()
std::vector<std::string> v_input = lengthedSplit(input);
With input as:
11:file_upload29:/home/user/Space Dir/file.out25:/home/user/Other Dir/blah
I had similar problem few days ago and solve it like this:
First I've created a copy, Then replace the quoted strings in the copy with some padding to avoid white spaces, finally I split the original string according to the white space indexes from the copy.
Here is my full solution:
you may want to also remove the double quotes, trim the original string and so on:
#include <sstream>
#include<iostream>
#include<vector>
#include<string>
using namespace std;
string padString(size_t len, char pad)
{
ostringstream ostr;
ostr.fill(pad);
ostr.width(len);
ostr<<"";
return ostr.str();
}
void splitArgs(const string& s, vector<string>& result)
{
size_t pos1=0,pos2=0,len;
string res = s;
pos1 = res.find_first_of("\"");
while(pos1 != string::npos && pos2 != string::npos){
pos2 = res.find_first_of("\"",pos1+1);
if(pos2 != string::npos ){
len = pos2-pos1+1;
res.replace(pos1,len,padString(len,'X'));
pos1 = res.find_first_of("\"");
}
}
pos1=res.find_first_not_of(" \t\r\n",0);
while(pos1 < s.length() && pos2 < s.length()){
pos2 = res.find_first_of(" \t\r\n",pos1+1);
if(pos2 == string::npos ){
pos2 = res.length();
}
len = pos2-pos1;
result.push_back(s.substr(pos1,len));
pos1 = res.find_first_not_of(" \t\r\n",pos2+1);
}
}
int main()
{
string s = "234 \"5678 91\" 8989";
vector<string> args;
splitArgs(s,args);
cout<<"original string:"<<s<<endl;
for(size_t i=0;i<args.size();i++)
cout<<"arg "<<i<<": "<<args[i]<<endl;
return 0;
}
and this is the output:
original string:234 "5678 91" 8989
arg 0: 234
arg 1: "5678 91"
arg 2: 8989

Splitting a string at a specified character and storing them in a vector

I'm working on my own string class and I'm having trouble with this "split" function. The idea is to pass a character, the function looks for the character, splits the string at every instance of it, then stores the resulting strings into a vector. For example. split('r') for the word tree would return a vector containing "t" and "ee". Here's my function:
std::vector<String> String::split(char c) const{
std::vector<String> result;
int start = 0, end;
int i = 0;
while(ptr[i] != 0) {
if(ptr[i] == c) {
end = i;
result.push_back(substr(start, end - 1));
start = end + 1;
}
++i;
}
result.push_back(substr(start, length() - 1));
return result;
}
Every time I run this, it gives me a bad_alloc error. Any ideas?
Edit 1: My substr() takes starting and ending position, unlike the std::string substr()

Find all possible versions of a string whose characters may have multiple variants

I'm looking for some tips on how to find all possible versions of a string whose characters may have multiple variants.
A simple example:
"Macao" is the starting string. The character 'a' has the variant 'ä', and the character 'o' has the variant 'ö'.
The goal is to obtain the following list from the above information:
Macao
Mäcao
Macäo
Mäcäo
Macaö
Mäcaö
Macäö
Mäcäö
My approach so far has been to identify and extract the characters with variants to simplify things. The idea is to work on the respective characters rather than the entire word.
aao
äao
aäo
ääo
aaö
äaö
aäö
ääö
The following code finds the variants that we are working with.
std::vector<std::string> variants;
variants.push_back("aä");
variants.push_back("oö");
std::string word = "Macao";
std::vector<std::string> results;
for (auto &variant : variants) {
for (auto &character : word) {
if (variant.front() == character) {
results.push_back(variant);
}
}
}
std::cout << "The following characters have variants: ";
for (auto &i : results) {
std::cout << i.front();
}
std::cout << std::endl;
The next step is to find all the possible combinations for the respective characters. To this end, I wrote the following function. It creates a new string out of the first character of each string in results.
std::string read_results(std::vector<std::string> &results)
{
std::string s;
for (auto &c : results) {
s.push_back(c.front());
}
return s;
}
The idea is to then change the strings stored in results in such a way as to get all the possible combinations, and that's where I'm stuck. I note that std::rotate seems like it would be helpful.
An inverted index may be useful.
You can store all the letters that have multiple variants in a vector, in order, and a vector with a grouping index for each letter, so that the i-th letter belongs to the group I[i], and all the letters whose index is the same than I[i] are variants from the same letter:
string L = "aoäöâô"; // disclaimer: i don't know if this is really in order
unsigned int I[] = {0,1,0,1,0,1};
// this means that "aäâ" belong to group 0, and "oöô" belong to group 1
You can build the inverted index for the previous L and I with something like this:
vector<vector<unsigned int> > groups;
// groups[k] stores the indices in L of the letters that belongs to the k-th group.
// do groups.reserve to make this operation more efficient
for(size_t i = 0; i < L.size(); ++i)
{
unsigned int idx = I[i];
if(idx <= groups.size()) groups.resize(idx+1);
groups[idx].push_back(i);
}
It is important that letters in L are in order, so you can do a binary search on it later, that takes O(logn) instead of O(n) of a usual loop. Then, once you have the group of your letter, you can find its variants with an inverted index:
char letter = 'a';
string::iterator it = std::lower_bound(L.begin(), L.end(), letter);
if(it != L.end() && *it == letter)
{
unsigned int idx = I[ it - L.begin() ];
// the letter has variants because it belongs to group idx
const vector<unsigned int>& group = groups[idx];
for(vector<unsigned int>::const_iterator git = group.begin();
git != group.end(); ++git)
{
// now, L[*git] is one of the variants of letter
...
}
}