urallsad
urallsad

Reputation: 115

How to know if a word in a string has digits?

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

Answers (6)

lmNt
lmNt

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

nikhil jain
nikhil jain

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

erol yeniaras
erol yeniaras

Reputation: 3795

There are plenty of methods that you can use. Below are some of them:

1 - A generic algorithm:

  1. Iterate through the string: For example: "My userID is john17 and my 4 digit pin is 1234 which is secret."

  2. 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,

  3. If you find a nondigit before reaching another space set IsNumberOnly=false,

  4. 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

SHR
SHR

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

Hiura
Hiura

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

Jerry Coffin
Jerry Coffin

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

Related Questions