Search code examples
pythonindex-error

String index out of range despite iterating within a range


I am trying to build a strong password checker using Python. The conditions of the password are as follows:

  • It has at least 6 characters and at most 20 characters.
  • It must contain at least one lowercase letter, at least one uppercase letter, and at least one digit.
  • It must NOT contain three repeating characters in a row ("...aaa..." is weak, but "...aa...a..." is strong, assuming other conditions are met).

Write a function strongPasswordChecker(s), that takes a string s as input, and return the MINIMUM change required to make s a strong password. If s is already strong, return 0.

Insertion, deletion or replace of any one character are all considered as one change.

The following is my attempt:

import re

class Solution:
    def strongPasswordChecker(self, s: str) -> int:

        # Holds the change
        change = 0

        # Checks if the password length is less than 6
        if len(s) < 6:
            change += 6 - len(s)

        # Checks if the password length is greater than 20
        elif len(s) > 20:
            change += len(s) - 20

        # Checks if the password has at least one digit
        elif re.search(r'\d', s):
            change += 1

        # Checks if the password has at least one upper case letter
        elif re.search(r'[A-Z]', s):
            change += 1

        # Checks if the password has at least one lower case letter
        elif re.search(r'[a-z]', password):
            change += 1

        # Checks for repeating characters
        for i in range(1, len(s)):
            if i >= 3 and i < len(s):
                if s[i] == s[i + 1] and s[i + 1] == s[i + 2]:
                    change += 1

        return change

Despite checking for the repeating characters with the if statement above, I'm still getting the following error:

IndexError: String Index out of range


Solution

  • The problem is this statement can go out of bounds potentially, for example when i == len(s) - 1 then s[i + 1] and s[i + 2] will both index out of bounds.

    for i in range(1, len(s)):
        if i >= 3 and i < len(s):
            if s[i] == s[i + 1] and s[i + 1] == s[i + 2]:
                change += 1
    

    If you want to make sure you don't have groups of 3 or longer, I'd use itertools.groupby

    >>> any(len(list(g)) > 2 for k, g in groupby('aabbcc'))
    False
    >>> any(len(list(g)) > 2 for k, g in groupby('aabbbbbcc'))
    True
    

    To replace your for loop in your code, you'd use this like

    elif any(len(list(g)) > 2 for k, g in groupby(s)):
        change += 1