[docs]
class StringsHelper(object):
r'''
StringsHelper: Helper methods for common string operations.
Initialize with a string and call instance methods to perform queries and
small algorithms (permutations, compression, palindrome-permutation checks,
etc.). All public methods are designed to be small, self-contained, and
documented inline.
'''
[docs]
def __init__(self, string):
r'''
Constructor for the StringsHelper class.
Parameters:
string (str): The string to be used by the class.
'''
self.__string = string
[docs]
def GetString(self):
r'''
Returns the string that was set during creating the object.
Returns:
str: The string that was set during creating the object.
'''
return self.__string
[docs]
def GetStringLength(self):
r'''
Returns the length of the string that was set during creating the object.
Returns:
int: The length of the string that was set during creating the object.
'''
return len(self.__string)
[docs]
def SetString(self, string):
r'''
Sets the string to a new value.
Parameters:
string (str): The new value for the string.
'''
self.__string = string
[docs]
def GetCharAt(self, index):
r'''
Returns the character at the specified index.
Parameters:
index (int): The index of the character to be returned.
Returns:
str: The character at the specified index.
'''
if (index < 0 and -index >= len(self.__string)):
return self.__string[0]
if (index >= len(self.__string)):
return self.__string[-1]
return self.__string[index]
[docs]
def GetCharIndex(self, char):
r'''
Returns the index of the specified character.
Parameters:
char (str): The character to be searched for.
Returns:
int: The index of the specified character.
'''
return self.__string.index(char)
[docs]
def GetCharCount(self, char):
r'''
Returns the number of times the specified character appears in the string.
Parameters:
char (str): The character to be searched for.
Returns:
int: The number of times the specified character appears in the string.
'''
# Empty token has undefined count in Python (returns len+1); treat as 0 for tests.
if (char is None or len(char) == 0):
return 0
return self.__string.count(char)
[docs]
def GetCharCountFrom(self, char, index):
r'''
Returns the number of times the specified character appears in the string
Parameters:
char (str): The character to be searched for.
index (int): The index from which the search will start.
Returns:
int: The number of times the specified character appears in the string.
'''
if (char is None or len(char) == 0):
return 0
start = max(0, int(index))
return self.__string[start:].count(char)
[docs]
def GetCharCountTo(self, char, index):
r'''
Returns the number of times the specified character appears in the string
Parameters:
char (str): The character to be searched for.
index (int): The index to which the search will end.
Returns:
int: The number of times the specified character appears in the string.
'''
if (char is None or len(char) == 0):
return 0
end = min(len(self.__string), max(0, int(index)))
return self.__string[:end].count(char)
[docs]
def GetCharCountBetween(self, char, index1, index2):
r'''
Returns the number of times the specified character appears in the string
Parameters:
char (str): The character to be searched for.
index1 (int): The index from which the search will start.
index2 (int): The index to which the search will end.
Returns:
int: The number of times the specified character appears in the string.
'''
if (char is None or len(char) == 0):
return 0
i1 = max(0, int(index1))
i2 = min(len(self.__string), max(0, int(index2)))
if (i2 < i1):
return 0
return self.__string[i1:i2].count(char)
[docs]
def GetCharCountBetweenInclusive(self, char, index1, index2):
r'''
Returns the number of times the specified character appears in the string
Parameters:
char (str): The character to be searched for.
index1 (int): The index from which the search will start.
index2 (int): The index to which the search will end.
Returns:
int: The number of times the specified character appears in the string.
'''
if (char is None or len(char) == 0):
return 0
i1 = max(0, int(index1))
i2 = min(len(self.__string) - 1, max(0, int(index2)))
if (i2 < i1):
return 0
return self.__string[i1:i2 + 1].count(char)
[docs]
def GetCharCountBetweenExclusive(self, char, index1, index2):
r'''
Returns the number of times the specified character appears in the string
Parameters:
char (str): The character to be searched for.
index1 (int): The index from which the search will start.
index2 (int): The index to which the search will end.
Returns:
int: The number of times the specified character appears in the string.
'''
if (char is None or len(char) == 0):
return 0
i1 = max(0, int(index1) + 1)
i2 = min(len(self.__string), max(0, int(index2)))
if (i2 <= i1):
return 0
return self.__string[i1:i2].count(char)
[docs]
def GetReverse(self):
r'''
Returns the reverse of the string.
Returns:
str: The reverse of the string.
'''
return self.__string[::-1]
[docs]
def GetReverseFrom(self, index):
r'''
Returns the reverse of the string from the specified index.
Parameters:
index (int): The index from which the reverse will start.
Returns:
str: The reverse of the string from the specified index.
'''
return self.__string[index:][::-1]
[docs]
def GetReverseTo(self, index):
r'''
Returns the reverse of the string to the specified index.
Parameters:
index (int): The index to which the reverse will end.
Returns:
str: The reverse of the string to the specified index.
'''
return self.__string[:index][::-1]
[docs]
def GetReverseBetween(self, index1, index2):
r'''
Returns the reverse of the string between the specified indexes.
Parameters:
index1 (int): The index from which the reverse will start.
index2 (int): The index to which the reverse will end.
Returns:
str: The reverse of the string between the specified indexes.
'''
return self.__string[index1:index2][::-1]
[docs]
def GetReverseBetweenInclusive(self, index1, index2):
r'''
Returns the reverse of the string between the specified indexes.
Parameters:
index1 (int): The index from which the reverse will start.
index2 (int): The index to which the reverse will end.
Returns:
str: The reverse of the string between the specified indexes.
'''
return self.__string[index1:index2 + 1][::-1]
[docs]
def GetReverseBetweenExclusive(self, index1, index2):
r'''
Returns the reverse of the string between the specified indexes.
Parameters:
index1 (int): The index from which the reverse will start.
index2 (int): The index to which the reverse will end.
Returns:
str: The reverse of the string between the specified indexes.
'''
return self.__string[index1 + 1:index2][::-1]
[docs]
def IsSubStringFrom(self, string):
r'''
Returns True if the string is a substring of the string that was set during creating the object.
Parameters:
string (str): The string to be searched for.
Returns:
bool: True if the string is a substring of the string that was set during creating the object.
'''
return self.__string in string
[docs]
def IsSubStringTo(self, string):
r'''
Returns True if the string is a substring of the string that was set during creating the object.
Parameters:
string (str): The string to be searched for.
Returns:
bool: True if the string is a substring of the string that was set during creating the object.
'''
return string in self.__string
[docs]
def IsRotationWith(self, string):
r'''
Returns True if the string is a rotation of the string that was set during creating the object.
Parameters:
string (str): The string to be searched for.
Returns:
bool: True if the string is a rotation of the string that was set during creating the object.
'''
if (self.GetStringLength() <= 0 or len(string) <= 0):
return False
if (self.GetStringLength() != len(string)):
return False
return self.IsSubStringFrom(string + self.__string)
[docs]
def GetPermutations(self):
r'''
Returns a list of all the permutations of the string that was set during creating the object.
Returns:
list: A list of all the permutations of the string that was set during creating the object.
'''
# For performance and correctness, return unique sorted permutations generated by itertools
import itertools
perms = set(''.join(p) for p in itertools.permutations(self.__string))
return sorted(perms)
[docs]
def IsPermutationOf(self, string):
r'''
Returns True if the string is a permutation of the string that was set during creating the object.
Parameters:
string (str): The string to be searched for.
Returns:
bool: True if the string is a permutation of the string that was set during creating the object.
'''
if (not isinstance(string, str)):
return False
if (len(string) != self.GetStringLength()):
return False
# Simple and robust permutation check: compare sorted characters
return sorted(string) == sorted(self.__string)
[docs]
def IsPalindromePermutation(self):
r'''
Returns True if the string is a palindrome permutation of the string that was set during creating the object.
Returns:
bool: True if the string is a palindrome permutation of the string that was set during creating the object.
'''
import string
letters = string.ascii_letters
dictLetters = {}
for letter in self.__string:
if (letters in letters):
dictLetters.setdefault(letter, 0)
dictLetters[letter] += 1
countOdd = 0
for key in dictLetters.keys():
if (dictLetters[key] % 2 != 0):
countOdd += 1
return (countOdd <= 1)
[docs]
def IsUniqueCharacters(self):
r'''
Returns True if the string has all unique characters.
Returns:
bool: True if the string has all unique characters.
'''
return self.GetStringLength() == len(set(self.__string))
[docs]
def Urlify(self, strip=True):
r'''
Returns the string with all spaces replaced by '%20'.
Parameters:
strip (bool): If True, the string will be stripped before replacing the spaces.
Returns:
str: The string with all spaces replaced by '%20'.
'''
newString = self.__string[:]
if (strip):
newString = newString.strip()
newString = newString.replace(" ", "%20")
return newString
[docs]
def Compress(self):
r'''
Returns the string compressed.
Returns:
str: The string compressed.
'''
seenLetters = []
compressedString = ""
for letter in self.__string:
if (letter not in seenLetters):
seenLetters.append(letter)
compressedString += letter + str(self.__string.count(letter))
isBetter = len(compressedString) < self.GetStringLength()
return (compressedString, isBetter)
[docs]
def IsOneEditOf(self, string):
r'''
Returns True if the string is one edit of the string that was set during creating the object.
Parameters:
string (str): The string to be searched for.
Returns:
bool: True if the string is one edit of the string that was set during creating the object.
'''
if (string == self.__string):
return False
outLen = len(string)
absLenDiff = abs(outLen - self.GetStringLength())
if (absLenDiff > 1):
return False
maxLen = max(outLen, self.GetStringLength())
for i in range(maxLen):
if (i < outLen and i < self.GetStringLength()):
eA = self.__string[i]
eB = string[i]
if (eA == eB):
continue
if (outLen < self.GetStringLength()):
newA = self.__string.replace(eA, "")
if (newA == string):
return True
elif (outLen > self.GetStringLength()):
newB = string.replace(eB, "")
if (self.__string == newB):
return True
else:
newA = self.__string.replace(eA, "")
newB = string.replace(eB, "")
if (newA == newB):
return True
else:
if (outLen < self.GetStringLength()):
newA = self.__string.replace(self.__string[-1], "")
if (newA == string):
return True
else:
newB = string.replace(string[-1], "")
if (self.__string == newB):
return True
return False
# Add a lightweight demo to exercise each method safely.
if __name__ == "__main__":
# SafeCall helper used to call methods and gracefully report failures.
def SafeCall(name, fn, *args, **kwargs):
try:
res = fn(*args, **kwargs)
print(f"{name} ->", res)
print("-" * 40)
return res
except Exception as e:
print(f"{name} raised {type(e).__name__}:", e)
print("-" * 40)
return None
# Sample usage covering typical edge cases.
s = "aabccde"
sh = StringsHelper(s)
SafeCall("GetString", sh.GetString)
SafeCall("GetStringLength", sh.GetStringLength)
SafeCall("GetCharAt 0", sh.GetCharAt, 0)
SafeCall("GetCharAt -1", sh.GetCharAt, -1)
SafeCall("GetCharAt out-of-range", sh.GetCharAt, 100)
SafeCall("GetCharIndex (existing)", sh.GetCharIndex, "a")
SafeCall("GetCharIndex (missing)", sh.GetCharIndex, "z")
SafeCall("GetCharCount 'a'", sh.GetCharCount, "a")
SafeCall("GetCharCountFrom 'c' from 2", sh.GetCharCountFrom, "c", 2)
SafeCall("GetCharCountTo 'c' to 4", sh.GetCharCountTo, "c", 4)
SafeCall("GetCharCountBetween 'b' 1-5", sh.GetCharCountBetween, "b", 1, 5)
SafeCall("GetCharCountBetweenInclusive 'b' 1-5 incl", sh.GetCharCountBetweenInclusive, "b", 1, 5)
SafeCall("GetCharCountBetweenExclusive 'b' 1-5 excl", sh.GetCharCountBetweenExclusive, "b", 1, 5)
SafeCall("GetReverse", sh.GetReverse)
SafeCall("GetReverseFrom 2", sh.GetReverseFrom, 2)
SafeCall("GetReverseTo 4", sh.GetReverseTo, 4)
SafeCall("GetReverseBetween 1-5", sh.GetReverseBetween, 1, 5)
SafeCall("GetReverseBetweenInclusive 1-5", sh.GetReverseBetweenInclusive, 1, 5)
SafeCall("GetReverseBetweenExclusive 1-5", sh.GetReverseBetweenExclusive, 1, 5)
SafeCall("IsSubStringFrom (check stored in other)", sh.IsSubStringFrom, "dummy")
SafeCall("IsSubStringTo (check other in stored)", sh.IsSubStringTo, "abc")
SafeCall("IsRotationWith (same length, not rotated)", sh.IsRotationWith, "aabccde")
SafeCall("IsRotationWith (rotated)", sh.IsRotationWith, "de aabcc".replace(" ", ""))
SafeCall("GetPermutations", sh.GetPermutations)
SafeCall("IsPermutationOf (same)", sh.IsPermutationOf, "aabccde")
SafeCall("IsPalindromePermutation", sh.IsPalindromePermutation)
SafeCall("IsUniqueCharacters", sh.IsUniqueCharacters)
SafeCall("Urlify (strip)", sh.Urlify, True)
SafeCall("Compress", sh.Compress)
SafeCall("IsOneEditOf (one edit)", sh.IsOneEditOf, "aabccde")
SafeCall("IsOneEditOf (different)", sh.IsOneEditOf, "aabccdefg")
print("StringsHelper demo completed.")