I am trying to solve the following problem:
Given a string str, the task is to check if the string is a valid
identifier or not. In order to qualify as a valid identifier,
the string must satisfy the following conditions:
It must start with either underscore(_) or any of the
characters from the ranges [‘a’, ‘z’] and [‘A’, ‘Z’].
There must not be any white space in the string.
And, all the subsequent characters after the first character
must not consist of any special characters like $, #, % etc.
Examples:
Input: str= “_code123”
Output: Valid
Input: str = “123code_”
Output: Invalid
My attempted solution, which works:
def isValid(str1, n):
# If first character is invalid
if (((ord(str1[0]) >= ord('a') and
ord(str1[0]) <= ord('z')) or
(ord(str1[0]) >= ord('A') and
ord(str1[0]) <= ord('Z')) or
ord(str1[0]) == ord('_')) == False):
return False
# Traverse the string for the rest of the characters
for i in range(1, len(str1)):
if (((ord(str1[i]) >= ord('a') and
ord(str1[i]) <= ord('z')) or
(ord(str1[i]) >= ord('A') and
ord(str1[i]) <= ord('Z')) or
(ord(str1[i]) >= ord('0') and
ord(str1[i]) <= ord('9')) or
ord(str1[i]) == ord('_')) == False):
return False
# is a valid identifier
return True
# Driver code
str1 = "_code123"
n = len(str1)
if (isValid(str1, n)):
print("Valid")
else:
print("Invalid")
How can I make the above code follow OOP principles, without so many nested ifs?
Have some read on regex it will help a lot for this kind of problem.
https://regexr.com/
This site is great for practice
import re
def isValid(str1):
res=re.match(r'^[_A-Za-z]\w+$',str1)
return res
str1 = "_code123"
n = len(str1)
if (isValid(str1)):
print("Valid")
else:
print("Invalid")
I think you can use that code.
if re.match('^[a-zA-Z_]+', line) is not None and re.match('^[\w-]+$', line) is not None:
return True
[a-zA-Z_]+ Your string may start with a-z, A-Z and underscore
There is nothing to say that nested ifs break OOP principles.
On the other hand, Python has certain features to help you out. First, you don't need to use ord so much because comparing two one-character strings does the same thing:
ord('a') < ord('b')
is equivalent to
'a' < 'b'
Second, Python allows you to chain math comparison operators, so instead of
'a' < 'b' and 'b' < 'c''
you can just type
'a' < 'b' < 'c'
But there is still an easier way: using the isalpha and isalphanumeric methods, you can avoid using the comparison operators, converting your code to:
Also, Python allows you to work directly on each character while looping by using the for c in str construct, saving you much indexing.
A more natural implementation of your code would be:
def is_valid(str1, n):
if not (str1[0] == '_' or str1[0].isalpha()):
return False
for c in str1[1:]:
if not (c == '_' or c.isalnum()):
return False
return True
You could even use a list comprehension for the second part, by doing:
if not all(c == '_' or c.isalnum() for c in str1[1:]):
return False
Related
def ul(a):
if a %2 == 0:
print(a.upper())
else:
print(a.lower())
ul(input())
I get following error:
TypeError: not all arguments converted during string formatting
I want to write every even letter in uppercase and every uneven letter in lowercase
What I'm doing wrong?
What you are now doing with this function is check whether the input (a string) is divisible by 2. This is not really what you wanted to do and it raises an error because strings are not modulo divisible.
You should better loop through the indices of the input string to fill a second string with upper and lower case letters:
def ul(s):
outstring = ''
for i in range(len(s)): ## For each index of the string
if i%2==0:
outstring += s[i].upper() ## Even indices become upper case
else:
outstring += s[i].lower() ## Odd indices become lower case
print(outstring)
ul(input("Enter a string: "))
You are trying to get mode of string as I understand. You should use len(a).
def ul(a):
if len(a) %2 == 0:
print(a.upper())
else:
print(a.lower())
ul(input())
Try this
def ul(a):
a = a.lower()
if ord(a) %2 == 0:
print(a.upper())
else:
print(a.lower())
if you want user to enter only Alphabets, then try this
def ul(a):
if ord(a) >= 110 and ord(a) < 123:
a = a.lower()
if ord(a) %2 == 0:
print(a.upper())
else:
print(a.lower())
else:
print("Please enter Alphabets only")
Input will give you a string. You want to use the modulo operator %, which is exactly how you usually find the evenness of a number. So, you are on the right track!
What actually happens is that Python interprets your % as the format operator (probably has a fancy name).
number = 2
print("Number %d is this" % number)
>>> Number 2 is this
Strings in Python are immutable, so you can't just change the string that easily.
Try this Replacing every 2nd character in a string , where you construct a new string by adding all the individual characters together.
def ul(word):
new = []
for i in range(len(word)):
if i%2 == 0:
new += word[i].upper()
else:
new += word[i].lower()
print("".join(new))
This will go through the string character by character, transform the individual character based on if it is even or not, and then construct a list "new", that holds all the individual characters. In the end, just join it, so create a new string out of the list.
There are more pythonic ways to do this using list comprehension, but for now this is easier to read and understand.
Write a function repfree(s) that takes as input a string s and checks whether any character appears more than once. The function should return True if there are no repetitions and False otherwise.
I have tried this but I don't feel this is an efficient way of solving it. Can you suggest an efficient code for this, thanks?
def repfree(s):
newlist = []
for i in range(0, len(s)):
newlist.append(s[i])
newlist2 = set(newlist)
if len(newlist) == len(newlist2):
print("True")
else:
print("False")
One easy way to meet this requirement is to use regular expressions. You may not be allowed to use them, but if you can, then consider this:
def repfree(s):
if re.search(r'^.*(.).*\1.*$', s):
print("True")
else:
print("False")
Believe it or not, this problem can be solved in O(1) time, because every sufficiently large string contains at least one duplicate character. There are only a finite number of different Unicode characters, after all, so a string cannot be arbitrarily long while also using each Unicode character at most once.
For example, if you happen to know that your strings are formed of only lowercase letters, you can do this:
def has_repeated_char(s):
return len(s) > 26 or len(s) != len(set(s))
Otherwise you can replace the 26 with whatever number of characters your string could possibly contain; e.g. 62 for upper- and lowercase letters and digits.
As of February 2020, the whole of Unicode has 137,994 distinct characters (Wikipedia), so if your string length is 150,000 then you can return True without searching.
Try
chars = 'abcdefghijklmnopqrstuvwxyz'
def repfree(s):
for char in chars:
count = s.count(char)
if count > 1:
return False
return True
But, this is a long way as it scans the list 26 times. A much better and Pythonic way would be
import collections
def repfree(s):
results = collections.Counter(s)
for i in results:
if results[i] > 1:
return False
return True
Here, results is a dictionary that contains all the characters of s as key, and their respective frequency as value. Further, it is checked if any value is greater than 1, repetition has occurred.
You could split the string characters to a set and compare the length
def repfree(s):
se = set(string)
print(len(se) == len(s))
You can make your approach more efficient by removing the for loop.
len(s) == len(set(s))
Otherwise, try using any
any(s.count(c) > 1 for c in s)
You could do this way:
Method 1:
def repfree(s):
if len(set(s)) == len(s):
return True
return False
Method 2:
def repfree(s):
return len(set(s)) == len(s)
Why set?
set will return the list of all unique characters in the string in sorted order
Example :
set('shubham')
Output:
{'a', 'b', 'h', 'm', 's', 'u'}
So,if a character in a string appears more than once,it will not be equal to the length of string itself.
def repfree(str):
l=list(str)
for i in range(len(l)):
check=str.count(l[i])
if check>1:
flag=1
else:
flag=0
if(flag==1):
return False
else:
return True
def matched(s):
stack = []
for char in s:
if char == '(':
stack.append(char)
elif char == ')':
if not stack:
return False
stack.pop()
return not stack
An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
is_isogram("Dermatoglyphics" ) == true
is_isogram("aba" ) == false
is_isogram("moOse" ) == false # -- ignore letter case
Here is my code:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
else:
return True
And when I tried to run the test code Test.assert_equals(is_isogram("moOse"), False, "same chars may not be same case" ) It failed, but I thought I did convert everything into lowercase. Can someone help?
Try this:
def is_isogram(string):
string = string.lower()
for char in string:
if string.count(char) > 1:
return False
return True
In your code when is_isogram("moose") is called, it will see that the first character's ('m') count is not greater than 1. So it will return True. Once it hits the return statement, it will stop the execution for the rest string. So you should really write return True only after for-loop to make sure that the function checks for the whole string.
If however, at any point, it finds a character's count to be greater than 1, then it will simply return False and stop executing because there's no point of checking any more when one point is found where condition does not hold.
How about using sets? Casting the string into a set will drop the duplicate characters, causing isograms to return as True, as the length of the set won't differ from the length of the original string:
def is_isogram(s):
s = s.lower()
return len(set(s)) == len(s)
print is_isogram("Dermatoglyphics")
print is_isogram("aba")
print is_isogram("moOse")
print is_isogram("")
This outputs:
True
False
False
True
Try this :
def is_isogram(s):
string = s.lower()
if len(s) == len(set(string)):
return True
return False
Try this out:
def is_isogram(string):
return len(string) == len(set(string.lower()))
"Implement a function that determines whether a string that contains only letters is an isogram."
By using sets, you can create unique elements. So if there are any repeating numbers, it will only select one. By calling len() on these strings, you can compare the length to the original.
Sorry if I explained it poorly. I am working on this.
let us define an isogram well:
according to wikipedia An Isogram is a word in which no letter occurs more than once.
check here for more about an isogram
just remind letter
I write this code and it works for me :
def is_isogram(argument):
print(len(argument))
if isinstance(argument,str):
valeur=argument.lower()
if not argument:
return False
else:
for char in valeur:
if valeur.count(char)>1 or not char.isalpha():
return False
return True
else:
raise TypeError("need a string ")
NB: the hidden test is the fact that you must check if the char in the string is a alpha character a-z, when i add this it pass all the hiddens tests
up vote if this help
I reckon this might not be the best solution in terms of maximizing memory space and time. This answer is just for intuition purposes using a dictionary and two for loops:
def is_isogram(string):
#your code here
#create an empty dictionary
m={}
#loop through the string and check for repeating characters
for char in string:
#make all characters lower case to ignore case variations
char = char.lower()
if char in m:
m[char] += 1
else:
m[char] = 1
#loop through dictionary and get value counts.
for j, v in m.items():
#if there is a letter/character with a count > 1 return False
if v > 1:
return False
#Notice the scope of the "return True" command. It is outside.
return True
Please don't give me the answer just point me in the right direction, thank you. Also, I need to do this without isdigit().
I am trying to create a program that checks all the characters of a string and if any of them are not natural numbers then the program will return False otherwise it will return True.
This is what i have so far:
numbers = ["0123456789"]
if len(str) > 0:
for i in str:
if i not in numbers:
return False
else:
return True
I have a few test cases and the problem I'm having is that when I return, the whole program just ends. I need to find a way to include the else: return True
You would need to remove the numbers from the list as you are comparing each character to all the digits at once i.e "1" == "0123456789" , you also need to check every char before returning True:
def is_dig(s):
numbers = "0123456789" # single iterable of the numbers
for i in s:
if i not in numbers:
return False
return bool(s) # return outside the loop also catching empty string
A more efficient approach would be to use the ord and all:
def is_dig(s):
return len(s) > 0 and all(48 <= ord(ch) <= 57 for ch in s)
The ord of "0" is 48 and the ord of "9" is 57 so if the ord of the char falls in that range then you have a digit, if not all will short circuit and return False.
Using the ord without all and following your own logic would look something like:
def is_dig(s):
if not s: # empty string
return False
for ch in s:
if not 48 <= ord(ch) <= 57:
return False
return True
numbers = "0123456789"
if len(str) > 0:
for i in str:
if i not in numbers:
return False
return True
Thanks Padraic and everyone for the input. #Till Hoffmann your answer was exactly what i was looking for
I have a function that decrements a whole number parameter represented by a string. For instance, if I pass in the string "100", it should return "99."
def dec(s):
i = len(s) - 1
myString = ""
while (i >= 0):
if s[i] == '0':
s[i] = '9'
i -= 1
else:
s[i] = chr(int(s[i]) - 1)
break
return s
However, Python issues this error.
s[i] = '9'
TypeError: 'str' object does not support item assignment
I am assuming that s[i] cannot be treated as an lvalue. What is a solution around this?
You can do:
s = s[:i] + "9" + s[i+1:]
This takes the part of the string before character index i, appends a 9, then appends the part of the string after character index i. However, doing a lot of string appends like this is not terribly efficient.
The other answer is that if you're dealing with numbers, why not actually use numbers instead of strings?
def dec(s):
return str(int(s) - 1)
Strings aren't mutable, but lists are. You can easily convert the string to a list of individual characters:
l = list(s)
Then convert it back:
s = ''.join(l)
Since you're working with a numeric string there are more direct approaches, but this answer works for the general case.
You can't. In Python, strings are immutable -- once created, they can't be changed.
You have two options without changing your function entirely.
Convert the string to a list and back:
def dec(s):
s = list(s)
i = len(s) - 1
myString = ""
while (i >= 0):
if s[i] == '0':
s[i] = '9'
i -= 1
else:
s[i] = chr(int(s[i]) - 1)
break
return ''.join(s)
Create a new string each time you want to make a change:
def dec(s):
i = len(s) - 1
myString = ""
while (i >= 0):
if s[i] == '0':
s = s[:i] + "9" + s[i+1:]
i -= 1
else:
s = s[:i] + chr(int(s[i]) - 1) + s[i+1:]
break
return s
I'm not sure why you are playing with the string character by character. Isn't this simpler?
def decrement_string(s):
try:
i = int(s)
i = i - 1
return str(i)
except:
# do something else
return "that's no number!"
while True:
s = raw_input("give me a number and I'll decrement it for you: ")
print decrement_string(s)
The solution to your specific problem of "decrementing" strings is to convert s to an int with int(s), decrease that, and convert back to a str: str(int(s)-1).
In [175]: str(int('100')-1)
Out[175]: '99'
The general solution is to not attempt to alter the elements of a string; use some other type to represent your work, and convert to a string as the last step.
Python strings are immutable so you cannot modify them. You have to create a new string that contains the value that you need. You are better off converting the string to an integer, decrementing it, and then converting it back to an integer again.
The reason for immutable strings is primarily efficiency.