0

When running this code below with input that includes both letters and numbers it prints not...

# test for both numbers and letters
def multi_test(analysis_input):
    alpha_test = False
    number_test = False
    if analysis_input.isalpha():
     alpha_test = True
     if analysis_input.isnumeric():
        number_test = True
        if alpha_test and number_test:
         print(analysis_input, 'is multiple characters')
        else:
         print('not')



analysis_input = input('enter your string argument')
multi_test(analysis_input)
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Br3xin
  • 116
  • 6
  • `isalpha()` only returns true if the _entire_ string is letters, and `isnumeric()` returns true only if the _entire_ string is numbers. If the string contains both, then neither method will return true. – John Gordon Jan 21 '22 at 22:39
  • That is because `isalpha` is only `True` if all characters in a string are letters. The same with `isnumeric`. Both can't be true at the same time, so you will always end in the `else`-part – eandklahn Jan 21 '22 at 22:39

3 Answers3

1

You need to check for each character:

def multi_test(analysis_input):
    alpha_test = False
    number_test = False
    for char in analysis_input:
        if char.isalpha():
            alpha_test = True
        if char.isnumeric():
            number_test = True
    if alpha_test and number_test:
        print(analysis_input,'is multiple characters')
    else:
        print('not')



analysis_input = input('enter your string argument')
multi_test(analysis_input)

EDIT: a perhaps faster and nicer method is using regex

^(?=.*[a-zA-Z]+)(?=.*\d+).+
# pseudo code, i'm not sure if this code works but its something like this
return bool(re.match(analysis_input, ^(?=.*[a-zA-Z]+)(?=.*\d+).+))

Idea from https://stackoverflow.com/a/24656216/10875953

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Robin Dillen
  • 704
  • 5
  • 11
0

For fun, here is an alternative strategy. Set up a list of the tests. For each char run all tests until one is a match. When one test is positive, remove it from the list of tests. When the list is empty, you've matched all requirements and can stop.

This method will have the advantage of only running the necessary tests and stopping as soon as you matched all tests once:

def multi_test(s):
    tests = [str.isalpha, str.isdigit]
    for char in s:   # for each character
        for i,test in enumerate(tests):
            if test(char):    # if test is positive
                tests.pop(i)  # remove it from the list of tests
                break
        if len(tests) == 0:  # if there is no test remaining
            return True      # this is a success, we're done
    return False

multi_test('abc1')
# True
mozway
  • 194,879
  • 13
  • 39
  • 75
  • Your approach got me thinking about a generator solution: `not any(test('abc1') for test in [str.isdigit, str.isalpha])`. Should also use early stopping in the built-in functions. – Michael Szczesny Jan 22 '22 at 02:12
  • @Michael clever approach but I see two drawbacks, it will output the wrong result with input like `'a.'`, and it can't generalize to add more than two exclusive tests ;) – mozway Jan 22 '22 at 06:56
0

You don't need to check every character. Your approach went in the right direction, but the indentation of the if statements and your logic could be improved. After removing the redundant parts you get

def multi_test(analysis_input):
    if analysis_input.isnumeric() or analysis_input.isalpha():
        print(analysis_input,'is not mixed')
    else:
        print(analysis_input,'is mixed characters')

Some test cases

for i in ['1234','12ab', 'abcd','1234abcd']:
    multi_test(i)

Output

1234 is not mixed
12ab is mixed charcters
abcd is not mixed
1234abcd is mixed charcters
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Michael Szczesny
  • 4,911
  • 5
  • 15
  • 32