Writing string comparing function in python - python

Im trying to write a function that get 2 arguments (2 strings actually) and compares them (ignoring the difference in upper/lower cases). For example:
cmr_func('House', 'HouSe')
true
cmr_func('Chair123', 'CHAIr123')
true
cmr_func('Mandy123', 'Mandy1234')
False.
Well, I tried something, but it seems very stupid and bad designed function, which anyway does not work. I would like to get idea. I believe i need to use some built-in str function, but im not sure how they can help me.
I thought about using in function with some loop. But i dont know on what kind of object should i apply a loop.
def str_comp(a,b):
for i in a:
i.lower()
for i in b:
i.lower()
if a == b:
print 'true'
else:
print 'false'
Any hint or idea are welcomed. Thanks :)

You can just convert both strings to lower-case and compare those results:
def str_comp (a, b):
return a.lower() == b.lower()
The idea behind this is normalization. Basically, you want to take any input string, and normalize it in a way that all other strings that are considered equal result in the same normalized string. And then, you just need to compare the normalized strings for equality.
Other operations you might consider are stripping whitespace (using str.strip()), or even more complex operations like converting umlauts to 2-letter combinations (e.g. ä to ae).
The problem with your solution is that you seem to assume that iterating over a string will allow you to modify the characters individually. But strings are immutable, so you cannot modify an existing string without creating a new one. As such, when you iterate over a string using for i in a you get many individual, independent strings for each character which are in no way linked to the original string a. So modifying i will not affect a.
Similarly, just calling str.lower() will not modify the string either (since it’s immutable), so instead, the function will return a new string with all letters converted to lower-case.
Finally, you shouldn’t return a string “True” or “False”. Python has boolean constants True and False which should be used for that. And if you use them, you don’t need to do the following either:
if condition:
return True
else:
return False
Since condition already is interpreted as a boolean, you can just return the condition directly to get the same result:
return condition

First you dont need to iterate the String to make all chars lowercase.
You can just:
a.lower()
b.lower()
Or you can do it all together:
def str_comp(a,b):
return a.lower() == b.lower()
Dont forget you're also returning True or False a Boolean, not returning a String (in this case the string "True" or "False")
If you want to return a String is function would different :
def str_comp(a,b):
if a.lower() == b.lower()
return "True"
return "False"

The function str.lower() actually works in a slightly different way:
This is no in-place modification. Calling a.lower() returns a copy of a with only lowercase letters and does not change a itself.
str.lower() can be called on whole strings, not just characters, so the for i in a loop won't be necessary.
Therefore you could simplify your function like following:
def str_comp(a, b):
if a.lower() == b.lower():
print 'true'
else:
print 'false'

def are_strings_equal(string_1, string_2):
return string_1.lower() == string_2.lower()

Related

Python - using Regex to return True if all substrings are contained within string

str = "chair table planttest"
substr = ["plant", "tab"]
x = func(substr, str)
print(x)
I want code that will return True if str contains all strings in the substr list, regardless of position. If str does not contain all the elements in substr, it should return False.
I have been trying to use re.search or re.findall but am having a very hard time understanding regex operators.
Thanks in advance!
You need to loop through all of the substrings and use the in operator to decide if they are in the string. Like this:
def hasAllSubstrings(partsArr, fullStr):
allFound = true
for part in partsArr:
if part not in fullStr:
allFound = false
return allFound
# Test
full = "chair table planttest"
parts = ["plant", "tab"]
x = hasAllSubstrings(parts, full)
print(x)
Let's see what the hasAllSubstrings function.
It creates a boolean variable that decides if all substrings have been found.
It loops through each part in the partsArr sent in to the function.
If that part is not in the full string fullStr, it sets the boolean to false.
If multiple are not found, it will still be false, and it won't change. If everything is found, it will always be true and not false.
At the end, it returns whether it found everything.
After the function definition, we test the function with your example. There is also one last thing you should take note of: your variables shouldn't collide with built-ins. You used the str variable, and I changed it to full because str is a (commonly used) function in the Python standard library.
By using that name, you effectively just disabled the str function. Make sure to avoid those names as they can easily make your programs harder to debug and more confusing. Oh, and by the way, str is useful when you need to convert a number or some other object into a string.
You can simply use the built-in function all() and the in keyword:
fullstr = "chair table planttest"
substr = ["plant", "tab"]
x = all(s in fullstr for s in substr)
In continuation to the answer of # Lakshya Raj, you can add break after allFound = false.
Because, as soon as the first item of the sub_strung is not found in str, it gives your desired output. No need to loop further.
allFound = false
break

How to check list of strings parameter type from isinstance() method

I want to try to handle the parameter type passed to the function by using isinstance() function. Basically, i want to check that whether passed list to the function contains only string or not. So, I wrote function as
def fun(parameter: list[str]):
#want to check parameter type here
After getting the list, I want to ensure that it contains only strings. So, is there any way to check this from isinstance() function? Otherwise i have to make custom check by looping through the list.
You could add an assertion, but yes, I think you need a loop
def fun(parameter:list[str]):
assert all(isinstance(s, str) for s in parameter)
This is kind of an odd, roundabout way of doing it, but here's how you could get away without using a loop. I prefer #OneCricketeer's answer in general though.
import numpy as np
def fun(parameter: list[str]):
assert list(np.array(parameter, dtype=str)) == parameter
...
Passing dtype=str will cause any non-string items in parameter to be converted to strings in the resulting array, which you can then convert back to a list and compare to the original. The two will be equal only if all items were strings already.
You could also use np.array_equal() instead of wrapping the array in list() and comparing with ==, which would be more efficient if your parameter list is very large.
You can use 2 methods:
Method 1: Using the built-in function of python3 i.e isinstance().\
example:
def fun(parameter: list[str]):
return isinstance(parameter, (list, str))
This will return the True or False. It will check parameter is list or string or a list of strings.
Method 2: create the custom function to check the type.
example:
def fun(parameter:list[str]):
if type(parameter) == list:
for i in parameter:
if type(i) != str:
return False
return True
return False
The logic behind the above code is simple it will check whether the parameter is list or not if a list will send False. If it is list then it will check the contains of the list are true or not. If they are true it simply returns True.

My program doesn't recognize .isdigit as True

In my program I want to check if the stroke symbol is a common digit (0-9)
.isnumeral works strange because it counts alphabeticals (a-z) as True, well then I lurked in and got that .isnumeral isn't actually searching exclusively for what I want - digits. And through the manual I found .isdigit but:
dna = 'a3'
start = 0
end = 1
if dna[end].isdigit is True:
print('Yes')
It's not working and 'Yes' isn't showing as expected.
if dna[end].isdigit is True:
isdigit() is a function, not an attribute.
You forgot the parentheses on the end, therefore you're referring to the function object itself, instead of the result of calling the function.
You must actually call the isdigit() method:
dna = 'a3'
start = 0
end = 1
if dna[end].isdigit():
print('Yes')
This gives your expected answer, True.
If you do dna[end].isdigit it just gives an object <built-in method isdigit of str object at address> which won't evaluate.
dna[end].isdigit in this case is referring to a str.isdigit function.
If you do print(type(dna[end].isdigit)) you will see what I mean.
To call the function instead, add paranthesis like this if dna[end].isdigit():
Two things:
there's no need to compare to true, just use the result from isdigit()
isdigit() is a function, which is truthy on its own, but does not equate to True
Check out the Python docs for more info.

Single specific character removal without slicing nor strip ,

how can i remove a single character from a string ?
Basically i have a string like :
abccbaa
I wish to remove the first and last letter. With the string.rstrip or string.lstrip methods all of the occurrences are removed and i get a string bccb. the same goes to replace.
is there a way of doing so ? i cannot import anything , i cant use slicing (except accessing single letter ) . Also I cannot use any kind of loops as well .
To get the whole picture , i need to write a recursive palindrome algorithm. My current code is:
def is_palindrome(s):
if s == '':
return True
if s[0] != s[-1]:
return False
else:
s = s.replace(s[0], '')
s = s.replace(s[-1], '')
return is_palindrome(s)
print is_palindrome("abccbaa")
as you can see it will work unless provides with a string like the one in the print line , since more than "edge" letters are stripped .
Slicing/replacing the string isn't needed and is costly because it creates strings over and over. In languages where strings are much less convenient to handle (like C), you wouldn't even have imagined to do like that.
Of course you need some kind of looping, but recursion takes care of that.
You could do it "the old way" just pass the start & end indices recursively, with a nested function to hide the start condition to the caller:
def is_palindrome(s):
def internal_method(s,start,end):
if start>=end:
return True
if s[start] != s[end]:
return False
else:
return internal_method(s,start+1,end-1)
return internal_method(s,0,len(s)-1)
recursion stops if start meets end or if checked letters don't match (with a different outcome of course)
testing a little bit seems to work :)
>>> is_palindrome("")
True
>>> is_palindrome("a")
True
>>> is_palindrome("ab")
False
>>> is_palindrome("aba")
True
>>> is_palindrome("abba")
True
>>> is_palindrome("abbc")
False
I'm taking a guess at what you are looking for here since your question wasn't all that clear but this works for taking off the first and last character of the word you provided?
Python 2.7.14 (default, Nov 12 2018, 12:56:03)
>>> string = "abccbaa"
>>> print(string[1:-1])
bccba

Python: List item is empty, code to detect if it is and then put in a place holder value?

Hey I'm writing a program that receives a broadcast from Scratch and then determines based on the broadcast, where to proceed. The code turns the broadcast(list item) into a string and then breaks that string into a list using .split(). The only problem is the broadcast may only be 1 word instead of 2. Is there a way to check if one of the list items from .split() is empty and then change it to a place holder value?
Where I am having trouble
scratchbroadcast = str(msg[1])
BroadcastList = scratchbroadcast.split()
#starts the switch statement that interprets the message and proceeds
#to the appropriate action
v = BroadcastList[0]
w = BroadcastList[1]
if BroadcastList[1] == '':
w = "na"
If BroadcastList contains only one word then BroadcastList will be a single-element list, e.g.
>>> "foo".split()
['foo']
Obviously we can't check whether the second item in the list is an empty string ''; there isn't a second element. Instead, check the length of the list:
w = "na" if len(BroadcastList) == 1 else BroadcastList[1]
Alternatively, use try to catch the IndexError (it's easier to ask for forgiveness than permission):
try:
w = BroadcastList[1]
except IndexError:
w = "na"
Okay, first consider this: how about the third item? Or the fourth? Or the forty-second?
If the string doesn't contain a splitter character (e.g. a space), you wouldn't end up with a list of two items, one of which blank -- you would end up with a list of only one item.
In Python, the length of something is generally obtained through the built-in len() function:
len([]) # == 0
len(["foo"]) # == 1
len(["foo", "bar"]) # == 2
Therefore, you would do:
if len(broadcast_list) == 1:
broadcast_list += [""]
Other ways of doing the same thing include broadcast_list.append("") and broadcast_list.extend([""]). Which one to use is completely up to you; += and .extend are more or less equivalent while .append can only add a single element.
Looking at the rest of your code, your case calls won't work like you expect them to: in Python, strings are truthy, so 'string' or 'otherString' is basically the same as True or True. or is strictly a boolean operator and you can't use it for 'either this or that'.
Python is notorious for not having a switch statement. Your attempt at implementing one would actually be kind of cute had you gone through with it -- something like that can be a pretty good exercise in Python OOP and passing functions as first-class objects. (In my day-to-day use of Python I hardly ever need to do something like that, but it's great to have it in your conceptual toolkit.)
You might be happy to learn that Python strings have a lower method; with it, your code would end up looking something like this:
v = broadcast_list[0].lower()
if v == 'pilight':
# ...
else if v == 'motor':
# ...
else if v == 'camera':
# ....
On a side note, you might want to have a look a PEP8 which is the de facto standard for formatting Python code. If you want other people to be able to quickly figure out your code, you should conform at least to its most basic propositions - such as classes being CamelCased and variables in lowercase, rather than the other way around.

Categories

Resources