Parse two or one number from std::string - c++

I'm stuck at designing this function:
//Turns "[0-9]+,[0-9]+" into two integers. Turns "[0-9]+" in two *equal* integers
static void parseRange(const std::string, int&, int&);
I don't have access to regular expressions (which would require either C++11 or Boost library). I need to somehow find out if the string contains 2 integers and split it, then get each integer.
I guess I'd need strstr version that uses std::string to find out if there's a comma and where. I could, probably, operate with std::string::c_str value. Extensive searching led me to this (but I want to use std::string, not C string):
void Generator::parseRange(const std::string str, int& min, int& max) {
const char* cstr = str.c_str();
const char* comma_pos;
//There's a comma
if((comma_pos=strstr(cstr, ","))!=NULL) { //(http://en.cppreference.com/w/cpp/string/byte/strstr)
//The distance between begining of string and the comma???
//Can I do this thing with pointers???
//Is 1 unit of pointer really 1 character???
unsigned int num_len = (comma_pos-cstr);
//Create new C string and copy the first part to it (http://stackoverflow.com/q/8164000/607407)
char* first_number=(char *)malloc((num_len+1)*sizeof(char));//+1 for \0 character
//Make sure it ends with \0
first_number[num_len] = 0;
//Copy the other string to it
memcpy(first_number, cstr, num_len*sizeof(char));
//Use atoi
min = atoi(first_number);
max = atoi(comma_pos+1);
//free memory - thanks #Christophe
free(first_number);
}
//Else just convert string to int. Easy as long as there's no messed up input
else {
min = atoi(cstr); //(http://www.cplusplus.com/reference/cstdlib/atoi/)
max = atoi(cstr);
}
}
I Googled a lot. You can't really say I didn't try. The function above works, but I'd prefer some less naive implementation, because what you see above is hardcore C code from the old times. And it all relies on fact that nobody messes up with input.

You can accomplish this by using the built in search facilities provided by std::string along with std::atoi without making copies or the need to use malloc or new to store parts of the string.
#include <cstdlib>
#include <string>
void Generator::parseRange(const std::string &str, int& min, int& max)
{
// Get the first integer
min = std::atoi(&str[0]);
// Check if there's a command and proces the second integer if there is one
std::string::size_type comma_pos = str.find(',');
if (comma_pos != std::string::npos)
{
max = std::atoi(&str[comma_pos + 1]);
}
// No comma, min and max are the same
else
{
max = min;
}
}
Alternatively as others have pointed out you can use std::istringstream to handle the integer parsing. This will allow you to do additional input validation when parsing the integer values
#include <sstream>
#include <string>
bool Generator::parseRange(const std::string& str, int& min, int& max)
{
std::istringstream sst(str);
// Read in the first integer
if (!(sst >> min))
{
return false;
}
// Check for comma. Could also check and error out if additional invalid input is
// in the stream
if (sst.get() != ',')
{
max = min;
return true;
}
// Read in the second integer
if (!(sst >> max))
{
return false;
}
return true;
}

What with this more native version:
void Generator::parseRange(const std::string str, int& min, int& max) {
stringstream sst(str);
if (!(sst>>min && sst.get()==',' && sst>>max))
cerr<<"String has an invalid format\n";
}

You can do all the searching and separating pretty easily with std::string functionality.
int pos = str.find(',');
assert(pos != std::string::npos);
std::string first = str.substr(0, pos);
std::string second = str.substr(pos+1, -1);
Alternatively, you can pretty easily do the parsing with a stringstream. For example:
std::istringstream s(str);
int one, two;
char ch;
s >> one >> ch >> two;
assert(ch == ',');
Note that this also makes it easy to combine separating the strings and converting the individual pieces into numbers.

No need for std::whatever, it will only consume more memory for a no less unreadable code.
Try this circa 1980 C code, it should do the trick:
void generator::parse_range (const std::string input, int & min, int & max)
{
const char * scan = input.c_str();
min = (int) strtol (scan, &scan, 0);
max = (*scan == ',') ? (int)strtol (scan+1, &scan, 0) : min;
if (errno || *scan != '\0') panic ("you call that numbers?");
}
This will accept hex or octal inputs, though you can fix the base with the 3rd parameter.
You could also check errno after first conversion or test for long integer overflow, but I assume this is not the worst part of your problem :)

Related

How to validate that there are only digits in a string?

I'm new to C++. I'm working on a project where I need to read mostly integers from the user through the console. In order to avoid someone entering non-digit characters I thought about reading the input as a string, checking there are only digits in it, and then converting it to an integer. I created a function since I need to check for integers several times:
bool isanInt(int *y){
string z;
int x;
getline(cin,z);
for (int n=0; n < z.length(); n++) {
if(!((z[n] >= '0' && z[n] <= '9') || z[n] == ' ') ){
cout << "That is not a valid input!" << endl;
return false;
}
}
istringstream convert(z); //converting the string to integer
convert >> x;
*y = x;
return true;
}
When I need the user to input an integer I'll call this function. But for some reason when I make a call tho this function the program doesn't wait for an input, it jumps immediately to the for-loop processing an empty string. Any thoughts? Thanks for your help.
There are many ways to test a string for only numeric characters. One is
bool is_digits(const std::string &str) {
return str.find_first_not_of("0123456789") == std::string::npos;
}
This would work:
#include <algorithm> // for std::all_of
#include <cctype> // for std::isdigit
bool all_digits(const std::string& s)
{
return std::all_of(s.begin(),
s.end(),
[](char c) { return std::isdigit(c); });
}
You can cast the string in a try/catch block so that if the cast fails you it would raise an exception and you can write whatever you want in the console.
For example:
try
{
int myNum = strtoint(myString);
}
catch (std::bad_cast& bc)
{
std::cerr << "Please insert only numbers "<< '\n';
}
Character-classification is a job typically delegated to the ctype facets of a locale. You're going to need a function that takes into account all 9 digits including the thousands separator and the radix point:
bool is_numeric_string(const std::string& str, std::locale loc = std::locale())
{
using ctype = std::ctype<char>;
using numpunct = std::numpunct<char>;
using traits_type = std::string::traits_type;
auto& ct_f = std::use_facet<ctype>(loc);
auto& np_f = std::use_facet<numpunct>(loc);
return std::all_of(str.begin(), str.end(), [&str, &ct_f, &np_f] (char c)
{
return ct_f.is(std::ctype_base::digit, c) || traits_type::eq(c, np_f.thousands_sep())
|| traits_type::eq(c, np_f.decimal_point());
});
}
Note that extra effort can go into making sure the thousands separator is not the first character.
try another way like cin.getline(str,sizeof(str)), and str here is char*. I think ur problem may be cause by other functions before calling this function. Maybe u can examine other parts of ur codes carefully. Breakpoints setting is recommended too.
Always use off-the-shelf functions. Never write alone.
I recommend
std::regex
Enjoy.

How to check what return functions and correctly calculate chars

Welcome. I have two problems. Firstly - function size bool (const char * pass) to check whether the amount of the chars inside of string is at least 8, but there is something wrong. Its always showing that there is minimum 8 chars, even is string contain only 3 chars.
My job is to create several small functions for checking the correctness of the entered string of chars. Can You help you with this one? If all small functions inside of bool check(...) return true i need to write in the console "STRING IS OKAY".
I will be grateful for any suggestions.
#include <iostream>
#include <cctype>
using namespace std;
//Check the amount of chars
bool size (const char* pass){
if(sizeof(pass) > 7)
return true;
}
//Checks if the ASCII are located between 32 to 126
bool isPrint (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(isprint(pass[x]))
return true;
}
}
//Check the amount of numbers
bool isNum (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(isdigit(pass[x]))
return true;
}
}
//Check the amount of Upper letters
bool isUpperLetter (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(isupper(pass[x]))
return true;
}
}
//Check the amount of lower letters
bool isLowerLetter (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(islower(pass[x]))
return true;
}
}
//Check the amount of Punctuation Marks
bool isPunctMark (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(ispunct(pass[x])){
return true;
}
}
}
//All small moduls together
bool check (const char* pass){
size(pass);
isPrint(pass);
isNum(pass);
isUpperLetter(pass);
isLowerLetter(pass);
isPunctMark(pass);
}
int main() {
char x;
cout << "Enter the string of characters" << endl;
cin >> x;
const char *password = &x;
check(password);
}
sizeof(pass) returns the size of the pointer. Which is implementation specific, and if your function is always returning true, we can guess that sizeof(char*) is 8, implying you have a 64-bit system.
On many other systems, it will return 4, or may even return 2 or 1, dependant on the architecture.
You probably want to check the length of the string the pointer is pointing to like so:
int len=strlen(pass);
if(len>=8) //Check for >=8 is clearer than >7)
{
return true;
}
You could also iterate over the string and check for null. But why bother when there is a nice std library routine that does the job.
to run all checks, do something like
bool isValid(const char* const pass)
{
if(!isPrint(pass))
{
return false;
}
if (!isNum(pass))
{
return false;
}
//etc
}
You could also have a big long
if(isPrint(pass)&&isNum(pass) .....)
{
return true;
}
but that would be messier, and harder to debug.
sizeof gives you the size of the type of the object passed to it. It is evaluated strictly at compile time. You are passing it a const char *, which is 8 on 64 bit systems.
To get the length of a C-style string, you can use the C function strlen, in the header <cstring>.
That said, I would recommend not doing this. I would recommend moving away from C strings to C++ std::strings, because they are much easier to use correctly.
Now as it is, you are very much using C strings INcorrectly!
int main() {
char x;
cout << "Enter the string of characters" << endl;
cin >> x;
const char *password = &x;
check(password);
}
You read a single char (x), then take its address and treat this as a C string. Now there are two significant problems here.
First, you probably meant to read more than one character.
Second, you will hit undefined behaviour, and your computer may well blow up, because C strings are supposed to be a pointer to a NUL-terminated array of char. Any functions that expect a C string will loop through look for an ending '\0', which x does not have, since it is not even an array in the first place.
So, if you use std::string from the <string> header, you can have much safer code, without all this faffing with pointers, NUL-terminators, and such.
(untested)
// one of your functions for example
bool isUpperLetter (const std::string& s){
for(int x=0; x < s.size(); ++x){ // Use <, not <=. C++ uses 0-indexing.
if(isupper(s[x]))
return true;
}
return false; // you forgot this!
}
int main() {
std::string s;
std::cout << "Enter a string:\n";
std::cin >> s;
isUpperLetter(s);
}
By the way, this won't work if your input string contains spaces, but one thing at a time!
(Next steps if you learn fast: Read up on std::getline and the <algorithm> header. std::count_if looks very relevant.)
And while we're at it, kill bad habits early, and read up on why you should avoid using namespace std; and std::endl.
EDIT
From your comment, you are stuck with the signature bool check(const char*), so I guess you are supposed to be learning about how to work with C strings. Let's for the moment assume your instructors know what they are doing.
Then the normal way to loop through a C string is with a pointer, checking for '\0'. So for instance, to count the number of uppercase letters (and really, you don't write it this way for real code. Or at least, if you tried to on a project I was working on I would strongly suggest you fix it):
int countUppercase (const char* c)
{
if(NULL==c) return 0;
int count = 0;
for ( ; '\0' != *c ; ++c ) // loop while not found the NUL
{
if (isupper(*c))
++count;
}
return count;
}
I still strongly recommend reading into a std::string if you can get away with it. If not, you're next best bet is probably std::istream::getline.
You are checking the sizeof(pass), which is size of const char*. You should iterate over the array and chack for str[i]=='\0' instead.
EDIT:
As suggested, you can also use strlen() function instead.
As there was already mentioned you use sizeof pointer in loops of your functions instead of the actual length of the passed string. Moreover sometimes comments before functions do not correspond what they do or have to do. For example
//Check the amount of numbers
bool isNum (const char* pass){
for(int x=0; x <= sizeof(pass); x++){
if(isdigit(pass[x]))
return true;
}
}
In the comment there is written "check the amount of numbers". I think you should return number of digits in the given string.
So I would rewrite the function the following way
//Check the amount of numbers
size_t DigitCount ( const char* pass )
{
size_t count = 0;
for ( ; *pass; ++pass )
{
if ( isdigit( *pass ) ) ++count;
}
return count;
}

istringstream invalid error beginner

I have this piece of code :
if(flag == 0)
{
// converting string value to integer
istringstream(temp) >> value ;
value = (int) value ; // value is a
}
I am not sure if I am using the istringstream operator right . I want to convert the variable "value" to integer.
Compiler error : Invalid use of istringstream.
How should I fix it ?
After trying to fix with the first given answer . it's showing me the following error :
stoi was not declared in this scope
Is there a way we can work past it . The code i am using right now is :
int i = 0 ;
while(temp[i] != '\0')
{
if(temp[i] == '.')
{
flag = 1;
double value = stod(temp);
}
i++ ;
}
if(flag == 0)
{
// converting string value to integer
int value = stoi(temp) ;
}
Unless you really need to do otherwise, consider just using something like:
int value = std::stoi(temp);
If you must use a stringstream, you typically want to use it wrapped in a lexical_cast function:
int value = lexical_cast<int>(temp);
The code for that looks something like:
template <class T, class U>
T lexical_cast(U const &input) {
std::istringstream buffer(input);
T result;
buffer >> result;
return result;
}
As to how to imitation stoi if your don't have one, I'd use strtol as the starting point:
int stoi(const string &s, size_t *end = NULL, int base = 10) {
return static_cast<int>(strtol(s.c_str(), end, base);
}
Note that this is pretty much a quick and dirty imitation that doesn't really fulfill the requirements of stoi correctly at all. For example, it should really throw an exception if the input couldn't be converted at all (e.g., passing letters in base 10).
For double you can implement stod about the same way, but using strtod instead.
First of all, istringstream is not an operator. It is an input stream class to operate on strings.
You may do something like the following:
istringstream temp(value);
temp>> value;
cout << "value = " << value;
You can find a simple example of istringstream usage here: http://www.cplusplus.com/reference/sstream/istringstream/istringstream/

How do I check if a C++ string is an int?

When I use getline, I would input a bunch of strings or numbers, but I only want the while loop to output the "word" if it is not a number.
So is there any way to check if "word" is a number or not? I know I could use atoi() for
C-strings but how about for strings of the string class?
int main () {
stringstream ss (stringstream::in | stringstream::out);
string word;
string str;
getline(cin,str);
ss<<str;
while(ss>>word)
{
//if( )
cout<<word<<endl;
}
}
Another version...
Use strtol, wrapping it inside a simple function to hide its complexity :
inline bool isInteger(const std::string & s)
{
if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
char * p;
strtol(s.c_str(), &p, 10);
return (*p == 0);
}
Why strtol ?
As far as I love C++, sometimes the C API is the best answer as far as I am concerned:
using exceptions is overkill for a test that is authorized to fail
the temporary stream object creation by the lexical cast is overkill and over-inefficient when the C standard library has a little known dedicated function that does the job.
How does it work ?
strtol seems quite raw at first glance, so an explanation will make the code simpler to read :
strtol will parse the string, stopping at the first character that cannot be considered part of an integer. If you provide p (as I did above), it sets p right at this first non-integer character.
My reasoning is that if p is not set to the end of the string (the 0 character), then there is a non-integer character in the string s, meaning s is not a correct integer.
The first tests are there to eliminate corner cases (leading spaces, empty string, etc.).
This function should be, of course, customized to your needs (are leading spaces an error? etc.).
Sources :
See the description of strtol at: http://en.cppreference.com/w/cpp/string/byte/strtol.
See, too, the description of strtol's sister functions (strtod, strtoul, etc.).
The accepted answer will give a false positive if the input is a number plus text, because "stol" will convert the firsts digits and ignore the rest.
I like the following version the most, since it's a nice one-liner that doesn't need to define a function and you can just copy and paste wherever you need it.
#include <string>
...
std::string s;
bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);
EDIT: if you like this implementation but you do want to use it as a function, then this should do:
bool has_only_digits(const string s){
return s.find_first_not_of( "0123456789" ) == string::npos;
}
You might try boost::lexical_cast. It throws an bad_lexical_cast exception if it fails.
In your case:
int number;
try
{
number = boost::lexical_cast<int>(word);
}
catch(boost::bad_lexical_cast& e)
{
std::cout << word << "isn't a number" << std::endl;
}
If you're just checking if word is a number, that's not too hard:
#include <ctype.h>
...
string word;
bool isNumber = true;
for(string::const_iterator k = word.begin(); k != word.end(); ++k)
isNumber &&= isdigit(*k);
Optimize as desired.
Use the all-powerful C stdio/string functions:
int dummy_int;
int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
if (scan_value == 0)
// does not start with integer
else
// starts with integer
You can use boost::lexical_cast, as suggested, but if you have any prior knowledge about the strings (i.e. that if a string contains an integer literal it won't have any leading space, or that integers are never written with exponents), then rolling your own function should be both more efficient, and not particularly difficult.
Ok, the way I see it you have 3 options.
1: If you simply wish to check whether the number is an integer, and don't care about converting it, but simply wish to keep it as a string and don't care about potential overflows, checking whether it matches a regex for an integer would be ideal here.
2: You can use boost::lexical_cast and then catch a potential boost::bad_lexical_cast exception to see if the conversion failed. This would work well if you can use boost and if failing the conversion is an exceptional condition.
3: Roll your own function similar to lexical_cast that checks the conversion and returns true/false depending on whether it's successful or not. This would work in case 1 & 2 doesn't fit your requirements.
Here is another solution.
try
{
(void) std::stoi(myString); //cast to void to ignore the return value
//Success! myString contained an integer
}
catch (const std::logic_error &e)
{
//Failure! myString did not contain an integer
}
Since C++11 you can make use of std::all_of and ::isdigit:
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string_view>
int main([[maybe_unused]] int argc, [[maybe_unused]] char *argv[])
{
auto isInt = [](std::string_view str) -> bool {
return std::all_of(str.cbegin(), str.cend(), ::isdigit);
};
for(auto &test : {"abc", "123abc", "123.0", "+123", "-123", "123"}) {
std::cout << "Is '" << test << "' numeric? "
<< (isInt(test) ? "true" : "false") << std::endl;
}
return 0;
}
Check out the result with Godbolt.
template <typename T>
const T to(const string& sval)
{
T val;
stringstream ss;
ss << sval;
ss >> val;
if(ss.fail())
throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
return val;
}
And then you can use it like that:
double d = to<double>("4.3");
or
int i = to<int>("4123");
I have modified paercebal's method to meet my needs:
typedef std::string String;
bool isInt(const String& s, int base){
if(s.empty() || std::isspace(s[0])) return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isPositiveInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
bool isNegativeInt(const String& s, int base){
if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
char * p ;
strtol(s.c_str(), &p, base) ;
return (*p == 0) ;
}
Note:
You can check for various bases (binary, oct, hex and others)
Make sure you don't pass 1, negative value or value >36 as base.
If you pass 0 as the base, it will auto detect the base i.e for a string starting with 0x will be treated as hex and string starting with 0 will be treated as oct. The characters are case-insensitive.
Any white space in string will make it return false.

How to replace all occurrences of a character in string?

What is the effective way to replace all occurrences of a character with another character in std::string?
std::string doesn't contain such function but you could use stand-alone replace function from algorithm header.
#include <algorithm>
#include <string>
void some_func() {
std::string s = "example string";
std::replace( s.begin(), s.end(), 'x', 'y'); // replace all 'x' to 'y'
}
The question is centered on character replacement, but, as I found this page very useful (especially Konrad's remark), I'd like to share this more generalized implementation, which allows to deal with substrings as well:
std::string ReplaceAll(std::string str, const std::string& from, const std::string& to) {
size_t start_pos = 0;
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
str.replace(start_pos, from.length(), to);
start_pos += to.length(); // Handles case where 'to' is a substring of 'from'
}
return str;
}
Usage:
std::cout << ReplaceAll(string("Number Of Beans"), std::string(" "), std::string("_")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("X")) << std::endl;
std::cout << ReplaceAll(string("ghghjghugtghty"), std::string("gh"), std::string("h")) << std::endl;
Outputs:
Number_Of_Beans
XXjXugtXty
hhjhugthty
EDIT:
The above can be implemented in a more suitable way, in case performance is of your concern, by returning nothing (void) and performing the changes "in-place"; that is, by directly modifying the string argument str, passed by reference instead of by value. This would avoid an extra costly copy of the original string by overwriting it.
Code :
static inline void ReplaceAll2(std::string &str, const std::string& from, const std::string& to)
{
// Same inner code...
// No return statement
}
Hope this will be helpful for some others...
I thought I'd toss in the boost solution as well:
#include <boost/algorithm/string/replace.hpp>
// in place
std::string in_place = "blah#blah";
boost::replace_all(in_place, "#", "#");
// copy
const std::string input = "blah#blah";
std::string output = boost::replace_all_copy(input, "#", "#");
Imagine a large binary blob where all 0x00 bytes shall be replaced by "\1\x30" and all 0x01 bytes by "\1\x31" because the transport protocol allows no \0-bytes.
In cases where:
the replacing and the to-replaced string have different lengths,
there are many occurences of the to-replaced string within the source string and
the source string is large,
the provided solutions cannot be applied (because they replace only single characters) or have a performance problem, because they would call string::replace several times which generates copies of the size of the blob over and over.
(I do not know the boost solution, maybe it is OK from that perspective)
This one walks along all occurrences in the source string and builds the new string piece by piece once:
void replaceAll(std::string& source, const std::string& from, const std::string& to)
{
std::string newString;
newString.reserve(source.length()); // avoids a few memory allocations
std::string::size_type lastPos = 0;
std::string::size_type findPos;
while(std::string::npos != (findPos = source.find(from, lastPos)))
{
newString.append(source, lastPos, findPos - lastPos);
newString += to;
lastPos = findPos + from.length();
}
// Care for the rest after last occurrence
newString += source.substr(lastPos);
source.swap(newString);
}
A simple find and replace for a single character would go something like:
s.replace(s.find("x"), 1, "y")
To do this for the whole string, the easy thing to do would be to loop until your s.find starts returning npos. I suppose you could also catch range_error to exit the loop, but that's kinda ugly.
For completeness, here's how to do it with std::regex.
#include <regex>
#include <string>
int main()
{
const std::string s = "example string";
const std::string r = std::regex_replace(s, std::regex("x"), "y");
}
If you're looking to replace more than a single character, and are dealing only with std::string, then this snippet would work, replacing sNeedle in sHaystack with sReplace, and sNeedle and sReplace do not need to be the same size. This routine uses the while loop to replace all occurrences, rather than just the first one found from left to right.
while(sHaystack.find(sNeedle) != std::string::npos) {
sHaystack.replace(sHaystack.find(sNeedle),sNeedle.size(),sReplace);
}
As Kirill suggested, either use the replace method or iterate along the string replacing each char independently.
Alternatively you can use the find method or find_first_of depending on what you need to do. None of these solutions will do the job in one go, but with a few extra lines of code you ought to make them work for you. :-)
What about Abseil StrReplaceAll? From the header file:
// This file defines `absl::StrReplaceAll()`, a general-purpose string
// replacement function designed for large, arbitrary text substitutions,
// especially on strings which you are receiving from some other system for
// further processing (e.g. processing regular expressions, escaping HTML
// entities, etc.). `StrReplaceAll` is designed to be efficient even when only
// one substitution is being performed, or when substitution is rare.
//
// If the string being modified is known at compile-time, and the substitutions
// vary, `absl::Substitute()` may be a better choice.
//
// Example:
//
// std::string html_escaped = absl::StrReplaceAll(user_input, {
// {"&", "&"},
// {"<", "<"},
// {">", ">"},
// {"\"", """},
// {"'", "'"}});
#include <iostream>
#include <string>
using namespace std;
// Replace function..
string replace(string word, string target, string replacement){
int len, loop=0;
string nword="", let;
len=word.length();
len--;
while(loop<=len){
let=word.substr(loop, 1);
if(let==target){
nword=nword+replacement;
}else{
nword=nword+let;
}
loop++;
}
return nword;
}
//Main..
int main() {
string word;
cout<<"Enter Word: ";
cin>>word;
cout<<replace(word, "x", "y")<<endl;
return 0;
}
Old School :-)
std::string str = "H:/recursos/audio/youtube/libre/falta/";
for (int i = 0; i < str.size(); i++) {
if (str[i] == '/') {
str[i] = '\\';
}
}
std::cout << str;
Result:
H:\recursos\audio\youtube\libre\falta\
For simple situations this works pretty well without using any other library then std::string (which is already in use).
Replace all occurences of character a with character b in some_string:
for (size_t i = 0; i < some_string.size(); ++i) {
if (some_string[i] == 'a') {
some_string.replace(i, 1, "b");
}
}
If the string is large or multiple calls to replace is an issue, you can apply the technique mentioned in this answer: https://stackoverflow.com/a/29752943/3622300
here's a solution i rolled, in a maximal DRI spirit.
it will search sNeedle in sHaystack and replace it by sReplace,
nTimes if non 0, else all the sNeedle occurences.
it will not search again in the replaced text.
std::string str_replace(
std::string sHaystack, std::string sNeedle, std::string sReplace,
size_t nTimes=0)
{
size_t found = 0, pos = 0, c = 0;
size_t len = sNeedle.size();
size_t replen = sReplace.size();
std::string input(sHaystack);
do {
found = input.find(sNeedle, pos);
if (found == std::string::npos) {
break;
}
input.replace(found, len, sReplace);
pos = found + replen;
++c;
} while(!nTimes || c < nTimes);
return input;
}
I think I'd use std::replace_if()
A simple character-replacer (requested by OP) can be written by using standard library functions.
For an in-place version:
#include <string>
#include <algorithm>
void replace_char(std::string& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::replace_if(std::begin(in), std::end(in),
[&srch](std::string::value_type v) { return v==srch; },
repl);
return;
}
and an overload that returns a copy if the input is a const string:
std::string replace_char(std::string const& in,
std::string::value_type srch,
std::string::value_type repl)
{
std::string result{ in };
replace_char(result, srch, repl);
return result;
}
This works! I used something similar to this for a bookstore app, where the inventory was stored in a CSV (like a .dat file). But in the case of a single char, meaning the replacer is only a single char, e.g.'|', it must be in double quotes "|" in order not to throw an invalid conversion const char.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int count = 0; // for the number of occurences.
// final hold variable of corrected word up to the npos=j
string holdWord = "";
// a temp var in order to replace 0 to new npos
string holdTemp = "";
// a csv for a an entry in a book store
string holdLetter = "Big Java 7th Ed,Horstman,978-1118431115,99.85";
// j = npos
for (int j = 0; j < holdLetter.length(); j++) {
if (holdLetter[j] == ',') {
if ( count == 0 )
{
holdWord = holdLetter.replace(j, 1, " | ");
}
else {
string holdTemp1 = holdLetter.replace(j, 1, " | ");
// since replacement is three positions in length,
// must replace new replacement's 0 to npos-3, with
// the 0 to npos - 3 of the old replacement
holdTemp = holdTemp1.replace(0, j-3, holdWord, 0, j-3);
holdWord = "";
holdWord = holdTemp;
}
holdTemp = "";
count++;
}
}
cout << holdWord << endl;
return 0;
}
// result:
Big Java 7th Ed | Horstman | 978-1118431115 | 99.85
Uncustomarily I am using CentOS currently, so my compiler version is below . The C++ version (g++), C++98 default:
g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
This is not the only method missing from the standard library, it was intended be low level.
This use case and many other are covered by general libraries such as:
POCO
Abseil
Boost
QtCore
QtCore & QString has my preference: it supports UTF8 and uses less templates, which means understandable errors and faster compilation. It uses the "q" prefix which makes namespaces unnecessary and simplifies headers.
Boost often generates hideous error messages and slow compile time.
POCO seems to be a reasonable compromise.
How about replace any character string with any character string using only good-old C string functions?
char original[256]="First Line\nNext Line\n", dest[256]="";
char* replace_this = "\n"; // this is now a single character but could be any string
char* with_this = "\r\n"; // this is 2 characters but could be of any length
/* get the first token */
char* token = strtok(original, replace_this);
/* walk through other tokens */
while (token != NULL) {
strcat(dest, token);
strcat(dest, with_this);
token = strtok(NULL, replace_this);
}
dest should now have what we are looking for.