Is there a way I can remove a character from a string? - c++

I want to remove a character ('#') from a string,
I tried to check if the string has '#' with the find function, which it does, then erase this with the erase function.
For some reason I get a run time error that says I have no memory.
Error: std::out_of_range at memory location 0x003BF3B4
#include <iostream>
#include <algorithm>
#include <string>
int main()
{
std::string str = "Hello World#";
if (str.find('#')) {
str.erase('#');
}
return 0;
}
The excepted output is: "Hello World"

Try something like this:
#include <algorithm>
str.erase(std::remove(str.begin(), str.end(), '#'), str.end());

#include <iostream>
#include <string>
#include <algorithm>
int main()
{
std::string s = "Hello World#";
char c = '#';
/* Removing character c from s */
s.erase(std::remove(s.begin(), s.end(), c), s.end());
std::cout << "\nString after removing the character "
<< c << " : " << s;
}

If you want to delete all '#' from the string:
std::string str = "Hello World#";
std::size_t pos = str.find('#');
while(pos != std::string::npos)
{
str.erase(pos, 1); //<- edited here
pos = str.find('#');
}
cout << str;

Related

Reverse Word Wise using basics of C++

The question Goes like this ( my code in the last )
Reverse the given string word wise. That is, the last word in given string should come at 1st place, last second word at 2nd place and so on. Individual words should remain as it is.
Input format :
String in a single line
Output format :
Word wise reversed string in a single line
Constraints :
0 <= |S| <= 10^7
where |S| represents the length of string, S.
Sample Input 1:
Welcome to Coding Ninjas
Sample Output 1:
Ninjas Coding to Welcome
Sample Input 2:
Always indent your code
Sample Output 2:
code your indent Always
This code is in c++:
void reverseStringWordWise(char input[])
{
// Length
int count=0;
for(int i=0; input[i]!='\0'; i++)
{
count++;
}
int len=count;
//reversing the complete string
int i=0;
int j=len-1;
while(i<j)
{
char temp=input[i];
input[i]=input[j];
input[j]=temp;
i++;
j--;
}
//individual reverse
int k=0;
int a,b;
for(;k<len;)
{
for(;input[k]==' ';k++)
{
b=k-1;
break;
}
while(a<b)
{
char temp=input[a];
input[a]=input[b];
input[b]=temp;
}
}
}
can someone help me with the logic of reversing the individual word, c or c++ works.
I would get rid of the char[]s and use std::string.
Example:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <list>
void reverseStringWordWise(std::string input) {
std::list<std::string> words;
for(auto sit = input.begin();;) {
// find a space from `sit` and forward
auto eit = std::find(sit, input.end(), ' ');
// store the word first in the list
words.emplace_front(sit, eit);
if(eit == input.end()) break; // last word, break out
sit = std::next(eit); // start next search after the found space
}
// print result
for(auto& word : words) std::cout << word << ' ';
std::cout << '\n';
}
int main() {
reverseStringWordWise("Hello world");
}
Output
world Hello
If you don't want the trailing space after the last word:
void reverseStringWordWise(std::string inp) {
std::list<std::string> words;
for (auto sit = inp.begin(), eit = sit; eit != inp.end(); sit = eit + 1) {
eit = std::find(sit, inp.end(), ' ');
words.emplace_front(sit, eit);
}
if(auto it = words.begin(); it != words.end()) {
std::cout << *it;
for(++it; it != words.end(); ++it) std::cout << ' ' << *it;
}
std::cout << '\n';
}
You can use the standard library algorithms to shorten the code. If you've got start and end iterators, you can use std::reverse, you can use std::strlen to calculate the end iterator and you can use std::find to identify the next word boundary. Assuming every word seperator is a space character, this could result in the following algorithm
void reverseStringWordWise(char input[])
{
if (input[0] == '\0')
{
return;
}
auto const end = input + std::strlen(input);
std::reverse(input, end);
auto wordEnd = input;
while(true)
{
auto wordStart = wordEnd;
wordEnd = std::find(wordStart, end, ' ');
std::reverse(wordStart, wordEnd);
if (wordEnd == end)
{
break;
}
++wordEnd;
}
}
int main() {
char input1[] = "Welcome to Coding Ninjas";
char input2[] = "Always indent your code";
reverseStringWordWise(input1);
reverseStringWordWise(input2);
std::cout << input1 << '\n'
<< input2 << '\n';
}
Here is another solution, using std::stack:
#include <stack>
#include <string>
#include <sstream>
#include <iostream>
void reverseStringWordWise(std::string input)
{
std::stack<std::string> wordStack;
std::istringstream strm(input);
std::string word;
// push each word on the stack
while (strm >> word)
wordStack.push(word);
// pop stack for each word
while (!wordStack.empty())
{
std::cout << wordStack.top() << ' ';
wordStack.pop();
}
}
int main()
{
reverseStringWordWise("Welcome to Coding Ninjas");
}
Output:
Ninjas Coding to Welcome
With boost, it's easier:
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string/join.hpp>
std::string reverse_words(std::string s)
{
boost::char_delimiters_separator<char> const sep(" ");
boost::tokenizer<boost::char_delimiters_separator<char>> const words(s, sep);
return boost::algorithm::join(std::reverse(words.begin(), words.end()), " ");
}
In C++, you are expected to use algorithms and not bother with rewriting everything from scratch (unless you are writing a library such as boost). Especially, as others mentioned, reading/writing to arrays directly is most often going to end up with errors (your code is missing several boundary checks).
Here is a modern C++ version. The algorithm is to reverse each word and then reverse the whole string. The code takes the string by value so it has a copy of the string and then modifies the string in-place and returns it. It uses no extra memory.
#include <iostream>
#include <string>
#include <algorithm>
std::string word_reverse(std::string s) {
auto it = s.begin();
while(it != s.end()) {
auto it2 = std::find(it, s.end(), ' ');
std::reverse(it, it2);
it = it2 + (it2 != s.end());
}
std::reverse(s.begin(), s.end());
return s;
}
int main() {
std::string s = "Always indent your code";
std::string t = word_reverse(s);
std::cout << s << std::endl;
std::cout << t << std::endl;
}
Use Regex:-
// ```c++
#include <regex>
#include <iterator>
#include <iostream>
#include <string>
using it = std::regex_iterator<std::string::const_reverse_iterator>;
int main() {
const std::string s = "Always indent your code.";
std::regex regex("[\\w]+");
for (auto i = it(s.rbegin(), s.rend(), regex); i != it(); ++i) {
auto w = i->str();
std::copy(std::rbegin(w), std::rend(w), std::ostream_iterator<char>(std::cout));
std::cout << ' ';
}
}

Get last part of URL

How would I get the last part of a URL?
Say the variable url is https://somewhere.com/stuff/hello.
How would I get hello from this?
Using rfind and substr
Maybe with
#include <iostream>
#include <string>
int main() {
std::string url{"https://somewhere.com/stuff/hello"};
std::cout << url.substr(url.rfind('/')+1);
return 0;
}
But only, if you have a / in front of the last part
#include <iostream>
#include <string>
int main() {
const std::string url("https://somewhere.com/stuff/hello");
const std::size_t indexLastSeparator = url.find_last_of("/");
if (indexLastSeparator != std::string::npos)
{
const std::string lastPartUrl = url.substr(indexLastSeparator+1); // +1 to not keep /
std::cout << lastPartUrl << '\n'; // print "hello"
}
}
With find_last_of() and substr()
references :
https://en.cppreference.com/w/cpp/string/basic_string/find_last_of
https://en.cppreference.com/w/cpp/string/basic_string/substr

no matching function for call to 'replace(std::basic_string<char>::iterator, std::basic_string<char>::iterator, char, int)'|

How can I change all \ to \\?
I want to make address to work with files:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string str = "C:\\user\\asd";
replace(str.begin(), str.end(), '\\', '\\\\');
cout << str;
return 0;
}
I am getting an error:
F:\c++\tests\regex\main.cpp|8|error: no matching function for call to 'replace(std::basic_string<char>::iterator, std::basic_string<char>::iterator, char, int)'|
How can I do this work with a char array in C++ (without a function)?
You are using std::replace(), which replaces values within a range of iterators. In this situation, you are using iterators from a std::string, so the value being searched for, and the value to replace it with, must both be single char values. However, '\\\\' is a multi-byte character, and thus can't be used as a char value. That is why you are getting the compiler error.
std::string has its own overloaded replace() methods, several of which can replace portions of the std::string with multi-character strings.
Try this instead, eg:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "C:\\user\\asd";
string::size_type pos = 0;
while ((pos = str.find('\\', pos)) != string::npos)
{
str.replace(pos, 1, "\\\\");
pos += 2;
}
cout << str;
return 0;
}
Live demo
However, you say you "want to make address to work with files", which implies to me that you want to create a file: URI. If so, then you need something more like this instead (this is a gross over-simplification, a proper URI generator would be more complex then this, as URIs have many rules to them, but this will get you started):
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
using namespace std;
const char* safe_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~!$&'()*+,;=:#/";
int main()
{
string str = "C:\\user\\ali baba";
replace(str.begin(), str.end(), '\\', '/');
string::size_type pos = 0;
while ((pos = str.find_first_not_of(safe_chars, pos)) != string::npos)
{
ostringstream oss;
oss << '%' << hex << noshowbase << uppercase << (int) str[pos];
string newvalue = oss.str();
str.replace(pos, 1, newvalue);
pos += newvalue.size();
}
str = "file:///" + str;
cout << str;
return 0;
}
Live demo

Counting the tokens when you tokenize the string in C++?

Java has this easy method to count the tokens that you tokenize:
import java.util.*;
public class Program
{
public static void main(String[] args)
{
String str =
"This is/some text/that I am/parsing/using StringTokenizer/.";
StringTokenizer strTok =
new StringTokenizer(str, "/", false);
System.out.println("Count...");
System.out.println(strTok.countTokens());
}
}
Output:Count...6
Is there any easy way to do in C++?
You could use std::istringstreamclass along with function std::getline. For example
#include <iostream>
#include <sstream>
#include <string>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
size_t count = 0;
std::string line;
while ( std::getline( is, line, '/' ) ) ++count;
std::cout << "There are " << count << " tokens" << std::endl;
}
The output is
There are 6 tokens
Or
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
std::vector<std::string> v;
std::string line;
while ( std::getline( is, line, '/' ) ) v.push_back( line );
std::cout << "There are " << v.size() << " tokens" << std::endl;
}
To build again the string from the vector you could use for example the following code
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
char s[] = "This is/some text/that I am/parsing/using StringTokenizer/.";
std::istringstream is( s );
std::vector<std::string> v;
std::string line;
while ( std::getline( is, line, '/' ) ) v.push_back( line );
std::cout << "There are " << v.size() << " tokens" << std::endl;
std::string s1;
bool first = true;
for ( const std::string &t : v )
{
if ( first ) first = false;
else s1 += '/';
s1 += t;
}
std::cout << s1 << std::endl;
}
Or you could use standard algorithm std::replace declared in header <algorithm> to replace one delimeter to another in the original string.
If your compiler does not support the range based for loop then you can write instead
for ( std::vector<std::string>::size_type i = 0; i < v.size(); i++ )
{
if ( i != 0 ) s1 += '/';
s1 += v[i];
}
You could try this:
std::vector<std::string> v(std::istream_iterator<std::string>(std::cin), {});
std::cout << "Count..." << v.size() << "\n";
This will of course tokenize at spaces, not at arbitrary separators. To split on arbitary separators, we need std::getline, but now we don't have an easy istream_iterator. Thankfully, this is a solved problem. So we write:
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
namespace detail
{
template <char Sep = '\n'>
class Line : public std::string
{
friend std::istream & operator>>(std::istream & is, Line & line)
{
return std::getline(is, line, Sep);
}
};
}
int main()
{
std::vector<std::string> v(std::istream_iterator<detail::Line<'/'>>(std::cin), {});
std::cout << "Count..." << v.size() << "\n";
for (auto const & s : v) std::cout << s << "\n";
}
If you want to tokenize an existing string rather than the standard input, use a string stream, i.e. replace std::cin with iss, where we have:
#include <sstream>
std::istringstream iss(my_input_string);

Parse delimited string

How can I get :
connect
100
username
example
from this string:
ngg://connect>100/username>example/
Using std::string::find with arguments "/" and ">" and std::string::substr with the found indexes.
This is a good start.
Adding an answer with strtok for the sake of diversity:
char str[] = "ngg://connect>100/username>example/";
char *s = strtok(str, ">/");
std::vector<std::string> tokens;
while (s = strtok(NULL, ">/"))
tokens.push_back(std::string(s));
This will split the string str into the desired tokens (discarding the first ngg:, like in the question).
Here's a working example of this code.
A possibility is boost::split():
#include <iostream>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp>
int main()
{
std::vector<std::string> tokens;
std::string s("ngg://connect>100/username>example/");
boost::split(tokens, s, boost::is_any_of("/>"));
// "connect" == tokens[2]
// "100" == tokens[3]
// "username" == tokens[4]
// "example" == tokens[5]
return 0;
}
ngg://connect>100/username>example/
If this format is fixed, then you can use std::sscanf as:
#include <iostream>
#include <cstdio>
int main()
{
char const *input = "ngg://connect>100/username>example/";
char const *input_format = "ngg://%[^>]>%d/%[^>]>%[^/]";
char connect[100], user[100], str[100]; //assuming max size is 100
int num;
if ( std::sscanf(input, input_format, connect, &num, user, str) != 4 )
{
std::cerr<<"error - number of tokens read must be equal to 4";
return 0;
}
std::cout << connect <<std::endl;
std::cout << num <<std::endl;
std::cout << user <<std::endl;
std::cout << str <<std::endl;
}
Output (online demo):
connect
100
username
example