2

How can I check in Python 3 that a string contains only characters/symbols from a given list?

Given:

  • a list allowedSymbols = ['b', 'c', 'z', ':']
  • an input string enteredpass = str(input("Enter"))

How do I check if enteredpass only contains characters from the list allowedSymbols?

smci
  • 32,567
  • 20
  • 113
  • 146
Subeen Regmi
  • 44
  • 1
  • 5
  • 1
    Possible duplicate of [Does Python have a string 'contains' substring method?](https://stackoverflow.com/questions/3437059/does-python-have-a-string-contains-substring-method) – Jan Christoph Terasa Jul 09 '19 at 23:34
  • @JanChristophTerasa and everyone: this is different. The OP has a **list** of `allowedSymbols = ['b', 'c', 'z', ':']`. Not another string `allowedSymbols = 'bcz:'` – smci Jul 09 '19 at 23:56
  • Subeen, please **don't call a list an array** (even if [w3schools](https://www.w3schools.com/python/python_arrays.asp) confuses the terminology for learners). Also, it would help your question not get wrongly closed as duplicate if you had showed an actual example list: `allowedSymbols = ['b', 'c', 'z', ':']` or whatever. – smci Jul 10 '19 at 00:04
  • Last tip about asking a question is instead of `enteredpass = str(input("Enter"))`, show us some example (positive and negative) inputs: `enteredpass1 = 'b:c::z:bc:'`, `enteredpass2 = 'bc:y:z'` – smci Jul 10 '19 at 00:11
  • @smci Well, converting one into the other is trivial. And when iterating over any of them they behave the same. – Jan Christoph Terasa Jul 10 '19 at 15:35
  • @JanChristophTerasa: **No they don't behave the same:** if allowedSymbols is instead a list of words, e.g. `['in', 'the', 'car']`, then `all(c in allowedSymbols for c in 'carpeting')` will be False! That's why I'm saying "testing a string against a list of (possibly multicharacter) symbols is different to just testing its letters". Hence, **"Check a string contains another string"** is a broad and vague spec, and that's why we need specific examples to make it MCVE. – smci Jul 11 '19 at 02:11
  • @smci I was talking about the explicit case here and not the general one. But I see your valid point. – Jan Christoph Terasa Jul 11 '19 at 03:40
  • @JanChristophTerasa: actually I should have given the example `all(c in allowedSymbols for c in 'carinthe') = False`. But yeah there is a conflict between the specific intent of the OP (for single symbols, don't use a list, just use a string) and the general intent of the question as stated. – smci Jul 11 '19 at 03:59

4 Answers4

5

The more Pythonic way is to use all(), it's faster, shorter, clearer and you don't need a loop:

allowedSymbols = ['b', 'c', 'z', ':']

enteredpass1 = 'b:c::z:bc:'
enteredpass2 = 'bc:y:z'

# We can use a list-comprehension... then apply all() to it...
>>> [c in allowedSymbols for c in enteredpass1]
[True, True, True, True, True, True, True, True, True, True]

>>> all(c in allowedSymbols for c in enteredpass1)
True
>>> all(c in allowedSymbols for c in enteredpass2)
False

Also note there's no gain in allowedSymbols being a list of chars instead of a simple string: allowedSymbols = 'bcz:' (The latter is more compact in memory and probably tests faster too)

But you can easily convert the list to a string with ''.join(allowedSymbols)

>>> allowedSymbols_string = 'bcz:'

>>> all(c in allowedSymbols_string for c in enteredpass1)
True
>>> all(c in allowedSymbols_string for c in enteredpass2)
False

Please see the doc for the helpful builtins any() and all(), together with list comprehensions or generator expressions they are very powerful.

smci
  • 32,567
  • 20
  • 113
  • 146
3

Use sets for membership testing: keep the symbols in a set then check if it is a superset of the string.

>>> allowed = {'b', 'c', 'z', ':'}
>>> pass1 = 'b:c::z:bc:'
>>> allowed.issuperset(pass1)
True
>>> pass2 = 'f:c::z:bc:'
>>> allowed.issuperset(pass2)
False
>>> allowed.issuperset('bcz:')
True
wwii
  • 23,232
  • 7
  • 37
  • 77
0

This should do it.

for i in enteredpass:
    if i not in allowedSymbols:
         print("{} character is not allowed".format(i))
         break

Not sure what you're looking for with the Score = score -5. If you want to decrease score by 5 if all entered characters are in the allowedSymbols list just put score = score - 5 on the same indentation level as the for loop, but at the end of the code after the if block.

Michael
  • 749
  • 1
  • 8
  • 22
0

I am not a python expert, but something below will work

 for c in enteredpass:
   if c not in allowedSymbols: 
      return 0
user2644503
  • 1,553
  • 1
  • 13
  • 11