Thread: Limiting to characters on a string

  1. #1
    Registered User
    Join Date
    Feb 2015
    Posts
    225

    Limiting to characters on a string

    I'm trying to set up a function in which you type in one character, but the character you type in is limited to the string input. Which is to say you can only put in characters that exist in the given string, but I'm not sure how to go about it. This is what I have so far, but it's not compiling.

    Code:
    char UserInputHandler::GetSingleCharacter(string limit) {
      std::string str;
      char letter;
      int i;
      bool loopend = false;
      while (loopend == false) {
        std::getline(std::cin, str);
        i = (int)str.length();
        if (std::string::npos == str.find_first_not_of(limit)) {
          if (i > 1) {
            std::cout << invalid_char_input() << std::endl;
          } else {
            letter = str[0];
            std::cout << "Character Entered: " << letter << endl;
            loopend = true;
          }
        } else {
            std::cout << char_not_allowed() << std::endl;
        }
      }
      return letter;
    }

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,632
    This is what I have so far, but it's not compiling.
    Why is it not compiling? Do you get some kind of warning or error messages? If so it would be extremely helpful if you posted them, all of them exactly as they appear in your development environment. It would also be helpful if you posted the smallest possible complete program that illustrates the problem, so we can compile and see the errors for ourselves if we so desire.


    Jim

  3. #3
    Registered User Alpo's Avatar
    Join Date
    Apr 2014
    Posts
    877
    It appears to work for me. the only possible thing I can see that might not compile is that you forgot the std:: prefix to the string parameter.

    The only logical confusion I have is if this if condition is correct? It seems superfluous since you are using the index [] operator to retrieve that character. (Not saying it's wrong, it might just be redundant).
    Code:
    if (i > 1) {std::cout << invalid_char_input() << std::endl;
    }
    I tested it with the following code, it worked correctly AFAIK:

    Code:
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    class UserInputHandler
    {
    public:
        char GetSingleCharacter(std::string limit);
        std::string invalid_char_input() 
        {
            return std::string("You must enter a single character.");
        }
        std::string char_not_allowed() 
        {
            return std::string("That character is forbidden.");
        }
    };
    
    char UserInputHandler::GetSingleCharacter(std::string limit)
    {
        std::string str;
        char letter;
        int i;
        bool loopend = false;
        while (loopend == false) {
            std::getline(std::cin, str);
            i = (int)str.length();
            if (std::string::npos == str.find_first_not_of(limit)) {
                if (i > 1) {
                    std::cout << invalid_char_input() << std::endl;
                } else {
                    letter = str[0];
                    std::cout << "Character Entered: " << letter << endl;
                    loopend = true;
                }
            } else {
                std::cout << char_not_allowed() << std::endl;
            }
        }
        return letter;
    }
    
    int main()
    {
        UserInputHandler uih;
        uih.GetSingleCharacter("abcd");
    }
    Last edited by Alpo; 02-26-2015 at 10:50 PM.
    WndProc = (2[b] || !(2[b])) ? SufferNobly : TakeArms;

  4. #4
    Registered User
    Join Date
    Feb 2015
    Posts
    225
    @jimblumberg

    Sorry about that. It had been working before I tried to make it based on the input string, so I figured it would be a very easy fix.

    @Alpo

    It worked, thanks! I just had to make it a std::string. The only other thing I need help with now is setting it so the string is empty by default--which is to say there's no limits at that point.

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    The only other thing I need help with now is setting it so the string is empty by default--which is to say there's no limits at that point.
    Assuming that find_first_not_of doesn't just break when you do that, because I'm not actually sure what happens if the argument is an empty string. You could use default args if there is no other problem.

    I would kinda rewrite it. I hate guessing about what the STL does:
    Code:
    char X::GetChar() {
      std::string s;
      while(true) {
        geline(std::cin, s);
        if (s.length() == 1)
          return s[0];
      }
    }
    
    char X::GetChar(std::string limit) {
      char c;
      do
        c = GetChar();
      while (std::string::npos == limit.find(c));
      return c;
    }
    Not saying it's better though. There shouldn't be much of a problem as long as these functions are written in terms of one another to avoid unnecessary code duplication.
    Last edited by whiteflags; 02-27-2015 at 05:22 AM.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    >>i = (int)str.length();
    I suggest you don't do this. Declare "i" to be the same type str.length() returns (i.e. size_t) or use C++11's auto. Many bugs have come from not matching type and signedness, so just be consistent and match it.
    Also declare "i" near first use. As it's not needed before this line and you initialize there, you should declare it there

    size_t i = str.length();
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Feb 2015
    Posts
    225
    Changed i. How does one set an empty string to start with? I've done it with ints and boolean before, but never an empty string.

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    A string is empty by simply default-constructing it, i.e.
    std::string s;

    You can check whether a string is empty by checking against an empty string (e.g. s == "") or using the member function empty().
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Erik Ingvoldsen View Post
    Changed i. How does one set an empty string to start with? I've done it with ints and boolean before, but never an empty string.
    In the context of a default argument you will have to do something like this:
    Code:
    char X::GetChar(std::string limit = "");
    This allows you to define a function that takes an argument, limit, that will be an empty string or something else. In place of a literal empty string ("") you can write std::string(). In fact any type T with a default constructor, it can be invoked in this context with T().

  10. #10
    Registered User
    Join Date
    Feb 2015
    Posts
    225
    Alright, well it's default on empty, but now I have a problem with how it treats empty strings. I'm trying to set it so that if the string is empty, it won't check if the character input is inside the string. And if the string is not empty, it will check. The problem is, it ignores the string completely now and will let the user input anything.

    Code:
    char UserInputHandler::GetSingleCharacter(std::string limit = "") {
      std::string str;
      char letter;
      bool loopend = false;
      while (loopend == false) {
        std::getline(std::cin, str);
        size_t i = str.length();
        if (limit == "") {
          if (i > 1) {
            std::cout << invalid_char_input() << std::endl;
          } else {
            letter = str[0];
            std::cout << "Character Entered: " << letter << endl;
            loopend = true;
          }
        } else if (std::string::npos == str.find_first_not_of(limit)) {
          if (i > 1) {
            std::cout << invalid_char_input() << std::endl;
          } else {
            letter = str[0];
            std::cout << "Character Entered: " << letter << endl;
            loopend = true;
          }
        } else {
            std::cout << char_not_allowed() << std::endl;
        }
      }
      return letter;
    }
    In the main method I have this:

    Code:
    UserInputHandler handler;
    handler.GetSingleCharacter("abcd");
    So it should only be letting me put in a, b, c, or d, but it's allowing me to put in e, f, g, etc. too.

  11. #11
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Quote Originally Posted by Erik Ingvoldsen View Post

    So it should only be letting me put in a, b, c, or d, but it's allowing me to put in e, f, g, etc. too.
    That makes logical sense if you think about it.
    Code:
     str.find_first_not_of("abcd");
    Find first not of returns the first thing in the string that isn't these things. If the first character is 'e', etc. it's going to return that.

    What you need to do is try to find the character in a list of acceptable characters. I've already done this in example code earlier in the thread.

  12. #12
    Registered User
    Join Date
    Feb 2015
    Posts
    225
    Sorry about that. I just wanted to try and do as much as I could with my own coding so I didn't just copy/paste something without understanding it.

    Code:
    char X::GetChar() {
      std::string s;
      while(true) {
        geline(std::cin, s);
        if (s.length() == 1)
          return s[0];
      }
    }
    Is this part a function within a function?

  13. #13
    Registered User Alpo's Avatar
    Join Date
    Apr 2014
    Posts
    877
    Quote Originally Posted by Erik Ingvoldsen View Post
    Sorry about that. I just wanted to try and do as much as I could with my own coding so I didn't just copy/paste something without understanding it.

    Code:
    char X::GetChar() {
      std::string s;
      while(true) {
        geline(std::cin, s);
        if (s.length() == 1)
          return s[0];
      }
    }
    Is this part a function within a function?
    It is just a normal function with a loop that collects input into the string, it returns the string on the condition the length is 1.

    The definition of the function looks like this:
    Code:
    return_type class_type::function_name (parameters...)
    {
        body
    }
    The function_name should be one of the functions (methods) declared in the class_name class, the :: operator specifies the scope the function_name belongs to.
    WndProc = (2[b] || !(2[b])) ? SufferNobly : TakeArms;

  14. #14
    Registered User
    Join Date
    Feb 2015
    Posts
    225
    Hmmm well the problem is, this seems to be two functions

    Code:
    char X::GetChar() {
      std::string s;
      while(true) {
        geline(std::cin, s);
        if (s.length() == 1)
          return s[0];
      }
    }
     
    char X::GetChar(std::string limit) {
      char c;
      do
        c = GetChar();
      while (std::string::npos == limit.find(c));
      return c;
    }
    And I need to have everything in one function. Is there a possible way to format it so that an empty string will allow everything?

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I'm sorry that the two functions is causing such a problem. We can forget about it though.

    This function looks okay:
    Code:
    char UserInputHandler::GetSingleCharacter(std::string limit = "") {
      std::string str;
      char letter;
      bool loopend = false;
      while (loopend == false) {
        std::getline(std::cin, str);
        size_t i = str.length();
        if (limit == "") {
          if (i > 1) {
            std::cout << invalid_char_input() << std::endl;
          } else {
            letter = str[0];
            std::cout << "Character Entered: " << letter << endl;
            loopend = true;
          }
        } else if (std::string::npos == str.find_first_not_of(limit)) {
          if (i > 1) {
            std::cout << invalid_char_input() << std::endl;
          } else {
            letter = str[0];
            std::cout << "Character Entered: " << letter << endl;
            loopend = true;
          }
        } else {
            std::cout << char_not_allowed() << std::endl;
        }
      }
      return letter;
    }
    Like I said before, you need to replace find first not of with find, though.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Limiting string length to output
    By TonyG in forum C Programming
    Replies: 8
    Last Post: 05-17-2011, 04:49 AM
  2. Replies: 5
    Last Post: 05-09-2010, 10:58 AM
  3. Limiting Characters in Edit Box :: MFC
    By kuphryn in forum Windows Programming
    Replies: 5
    Last Post: 06-02-2002, 10:21 AM
  4. Limiting the number of characters typed
    By johnnyd in forum C Programming
    Replies: 10
    Last Post: 04-03-2002, 08:21 PM
  5. Concatenating: characters->string->vector (string) :: C++
    By kuphryn in forum C++ Programming
    Replies: 2
    Last Post: 02-02-2002, 01:14 PM