Reputation: 115
The question I have: How can you tell if a word in a string has a digit in it or not?
What I need to do: write a program that reads in a line of text and outputs the line with all the digits in all integer numbers replaced with 'x'.
For example:
My userID is john17 and my 4 digit pin is 1234 which is secret.
It should become
My userID is john17 and my x digit pin is xxxx which is secret.
Notice how the digits in john17 does not get affected.
The code I have so far:
#include <iostream>
using namespace std;
int main()
{
string str;
int i;
cout << "Enter a line of text: ";
getline(cin, str);
for (i = 0; i <= str.length(); i++)
{
if (str[i] >= '0' && str[i] <= '9')
{
str.at(i) = 'x';
}
}
cout << "Edited text: " << str << endl;
}
Upvotes: 6
Views: 1852
Reputation: 3892
Another alternative using the find_first_of
and find_first_not_of
. Will work no matter where the digits are in the word:
#include <iostream>
#include <sstream>
int main()
{
std::string str = "M3y u1serID is 7j2ohn17 and my 4 digit pin is 1234 which is secret.";
std::istringstream iss(str);
std::string word;
while(iss >> word)
{
if (word.find_first_not_of("0123456789") == std::string::npos) {
std::cout << std::string(word.size(), 'x') << " ";
} else {
std::cout << word << " ";
}
}
}
Upvotes: 1
Reputation: 105
Does your input format is always Look like this?
My userID is john17 and my 4 digit pin is 1234 which is secret.
Then just check whether there is a space before the digits or not. If yes then change the number with xxxxx else not.
Upvotes: 0
Reputation: 3795
There are plenty of methods that you can use. Below are some of them:
1 - A generic algorithm:
Iterate through the string:
For example: "My userID is john17 and my 4 digit pin is 1234 which is secret."
Set a boolean flag (IsNumberOnly=true
)when you find a digit immediately after a space
character and start caching the word. Please note that the flag is false
originally. For example the second '1'
in your example is a digit immediately after a space
character. Continue iterating,
If you find a nondigit before reaching another space
set IsNumberOnly=false
,
Finish the word. If IsNumberOnly=true
then print 'x'
s (the number of characters in the word cashed) else print the cashed word, e.g., 17John
.
Please note that here john17
will not be affected at all. Even it was 17john
it would not have been affected.
OR
2 - If you want to use The Library and C++11 then you can read and test the words one by one with:
std::all_of(str.begin(), str.end(), ::isdigit); // C++11
For more details and examples:
http://en.cppreference.com/w/cpp/algorithm/all_any_none_of
OR
3 - Something like this will do the trick:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string str;
cout << "Enter a line of text: ";
getline(cin,str);
istringstream iss(str);
string word;
string finalStr="";
while(iss >> word) {
if(word.find_first_not_of( "0123456789" ) == string::npos)
{
for(int i=0; i<word.size(); i++)
{
finalStr+='x';
}
}
else
{
finalStr.append(word);
}
finalStr+=' ';
}
cout << "Edited text: " << finalStr << endl;
return 0;
}
Those are all just some examples.
Hope that helps!
Upvotes: 2
Reputation: 8313
You can do something like this:
for any digit you found, check if it starting new word.
if it does, replace till the sequence of digits end.
it will work if name can't start with a digit.
for example:
for( size_t i=str.find_first_of("0123456789"); i!=string::npos; i=str.find_first_of("0123456789",i+1)){
if (i == 0 || str.at(i-1) == ' '){
do{
str.at(i) = 'x';
i++;
}while( isdigit( str.at(i)));
}
}
Upvotes: 1
Reputation: 3530
As always, STL provide many tools to do it relatively easily.
Here I show how to use stream iterator, all_of algorithm combined with isdigit predicate. The idea is to tokenise the input into words and if all character of the token are digits then replace it with x's.
#include <iostream>
#include <iterator>
#include <algorithm>
#include <locale>
int main(int, char**)
{
using iterator = std::istream_iterator<std::string>;
auto const& end = iterator();
for (auto it = iterator(std::cin); it != end; ++it) {
auto const& token = *it;
if (std::all_of(std::begin(token), std::end(token), [](auto&& c) { return std::isdigit(c, std::locale()); })) {
std::cout << std::string(token.size(), 'x') << " ";
} else {
std::cout << token << " ";
}
}
return 0;
}
And you can see it live here.
Upvotes: 1
Reputation: 490148
I'd probably use std::all_of
along with std::isdigit
, something like this:
std::string input("My userID is john17 and my 4 digit pin is 1234 which is secret.");
std::istringstream buffer(input);
std::transform(std::istream_iterator<std::string>(buffer),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, " "),
[](std::string const &s) -> std::string {
if (std::all_of(s.begin(), s.end(), isdigit))
return std::string(s.length(), 'x');
return s;
});
Note that as it stands right now this has undefined behavior: if your input includes any characters that are negative numbers when encoded into char
(e.g., characters with accents, umlauts, etc. in ISO 8859-*) then the behavior of isdigit
is undefined. Each character must be cast to unsigned char
before being passed to isdigit
to give defined behavior in such cases.
Upvotes: 1