Pass Variables within Python Class - python

I have the following class. But when trying to pass the variable x to the re.match it doesnt appear to correctly work as whatever input I put in it returns "invalid"
class validate:
def __init__(self, input_value):
self.input_value = input_value
def macaddress(self, oui):
self.oui = oui
#oui = 0, input deemed valid if it matches {OUI:DEVICE ID}.
#oui = 1, input deemed valid if it matches {OUI}.
if self.oui == 0:
x = 5
elif self.oui == 1:
x = 2
if re.match("[0-9a-fA-F]{2}([.-: ][0-9a-fA-F]{2}){x}$", self.input_value):
return "valid"
else:
return "invalid"
Should I be passing var x in some other manner ?
Thanks,

Insert x into the string this way (using string formatting):
Python <2.7:
if re.match("[0-9a-fA-F]{2}([.-: ][0-9a-fA-F]{2}){%d}$" % x, self.input_value):
However if you use the python 3 way of formatting, your regex interferes.
It can be cleaner (but slower) to use concatenation.
Without concatenation:
if re.match("[0-9a-fA-F]\{2\}([.-: ][0-9a-fA-F]\{2\}){0}$".format(x), self.input_value):
With concatenation:
if re.match("[0-9a-fA-F]{2}([.-: ][0-9a-fA-F]{2})" + x + "$", self.input_value):
Note: this fails if implicit type conversion is not possible.
If you just put {x} in the middle of your string, Python doesn't actually do anything with it unless string formatting is applied.

Related

Python return regexp-formatted string

There is an input string like "2r-rj1225-f11e-12-x-w"
The task is to return it in the following format:
all groups except the first and last must be 5 characters
the first and the last groups must be between 1 and 5 characters
if the first group in the input is less than 5 characters, it must be preserved
that results to is "2r-rj122-5f11e-12xw"
import re
string = "2r-rj1225-f11e-12-x-w"
baseLength = 5
def formatKey(string: str, baseLength: int) -> str:
p = re.compile(r"{1,baseLength}[a-zA-Z0-9]{baseLength}[a-zA-z0-9]+")
formatted = '-'.join(p.match(string))
return formatted
print(f'The reformatted string is {formatKey(string, baseLength)}')
that does not work, naturally. And I also wish to avoid '-'.join and to simply return something like regexp(re.compile('[a-z]FORMATREGEXP'), string) where FORMATREGEXP is the regexp that does the job.
Clarification: The actual solution is to use re.sub(pattern, repl, string) function: "The sub() function searches for the pattern in the string and replaces the matched strings with the replacement" -- And that is exactly what I've been asking for, that simple, in one line!!
I don't really see this as a regex problem. It's just reorganizing the characters after the first hyphen.
x = "2r-rj1225-f11e-12-x-w"
def reencode(x):
parts = x.split('-')
p1 = ''.join(parts[1:])
s = parts[0]
while len(p1) >= 5:
s += '-' + p1[:5]
p1 = p1[5:]
if p1:
s += '-' + p1
return s
print(reencode(x))
Output:
2r-rj122-5f11e-12xw

Why doesn't my specific implementation work for returning middle letter from a function?

The aim is to return the middle letter of a string, or " " if the string's even. I'm failing to see why my code doesn't work. Any sort of clarification would be great, thanks!
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if isinstance(z,int)==True:
return (ml[z-1])
else:
return (" ")
print (mid("abc"))
/ doesn't return an int; even if the number it returns can be represented as one:
>>> 4 / 2
2.0 # A float
It would be better to explicitly check if the number is even or not:
# Read as: "If z is odd", or, "If division of z by 2 has a remainder of 1"
if z % 2 == 1:
return ml[z-1]
else:
return " "
This behavior occurs, because the / operator returns a float. Although the smarter way to solve this would be the use of the modulo operator, if you want to stick to your code, could use the is_integer() method of float like this:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
if z.is_integer():
return (ml[int(z)-1])
else:
return (" ")
print (mid("abc"))
Better way to do it:
def mid(ml):
return ml[len(ml)//2] if len(ml) % 2 else ""
Following the answer from #Carcigenicate above you can try following code:
def mid(ml):
x=len(ml)
y=x+1
z=y/2
return (ml[int(z-1)])
print (mid("abc"))

How to check for certain things in my string?

My code is supposed to return None if the string:
Contains non-supported operators or non-numbers. Supported operators are: **,* , ^ , - , + , / , ( , )
Examples
"4.0 + 2" is valid
"3.88327 - $3.4" is invalid (since "$")
"a + 24" is invalid (since "a")
"2+6" is valid
"4+/3" is invalid (since "+/" is two operators next to each other)
"4**-3" is valid
How would I do this?
Here's my code:
def checkvalid(string1):
temp = string1.split()
for i in len(temp):
if i in "*^-+/()":
return None
if not i.isnumeric():
return None
return string1
But this doesn't always work. It only works for regular integer numbers like "22 66" -> this works, it returns the string, but nothing else seems to work, it always returns None.
Updated Answer
Since my original answer, you've added seven new requirements to this question. I'm disengaging as I think you need to better understand the scope of the problem you're facing before asking for more help.
However, I will throw one more snippet up that might set you on the right path, as it appears that you're trying to find valid mathematical expressions. The following code will do that:
def check_valid(data):
errors = (SyntaxError, NameError)
try:
eval(data)
except errors:
for i in data.split():
try:
eval(i)
except errors:
return None
return data
test = ["4++2", "4+-2", "4.0 + 2", "3.88327 - $3.4", "a + 24", "2+6", "4+/3"]
for t in test:
try:
assert check_valid(t)
print(f"{t} valid")
except AssertionError:
print(f"{t} not valid")
Output
4++2 valid
4+-2 valid
4.0 + 2 valid
3.88327 - $3.4 not valid
a + 24 not valid
2+6 valid
4+/3 not valid
In Python, + can repeat any number of times and still be a valid math expression, as it's just changing the sign of the integer repeatedly.
Original Answer
There are a number of ways to approach this. Given your example, there are a few flaws in your logic:
"4.0" is not numeric. Numeric is in 0-9 or unicode numerics. Docs here
You're checking a string against another string with the in keyword. With your first example string, the sequence "4.0" is clearly not in the sequence "*^-+/()". Example of how this works:
>>> "4.0" in "asdf4.012345"
True
>>> "4.0" in "0.4"
False
A quick fix using similar logic would be to check character-by-character rather than word-by-word, and combine the two conditionals with and. Try the following snippet:
def check_valid(data):
for word in data.split():
for character in word:
if character not in "*^-+/()." and not character.isnumeric():
return None
return data
test = ["4.0 + 2", "3.88327 - $3.4", "a + 24", "22 66", "2+6"]
for t in test:
print(f"Test: {check_valid(t)}")
Output
Test: 4.0 + 2
Test: None
Test: None
Test: 22 66
Test: 2+6
Note: I changed some names to more closely follow python code style best practices.
Adding a few checks to your eval can make it a bit more secure although not ideal.
import re
def checkvalid(string1):
string1 = string1.replace(" ", "")
checkStatements = ["++", "-+", "---"]
checkOut = [x for x in checkStatements if x not in string1]
# If you require anything further characters to be avoided place them in the regex
if re.match('[a-zA-Z]', string1) or len(checkOut) != len(checkStatements):
return False
else:
try:
output = eval(string1)
if isinstance(output, float) or isinstance(output, int):
return True
else:
return False
except:
return False
An alternative might be to use regex to check if the expression contains invalid characters; or to use a string parser.
Because your expressions are simple, let's make python do our job
def check_valid(expression: str):
try:
eval(expression) # Execute the expression; If the expression is valid, return the result of the evaluation; if is invalid; raise exception
return True
except Exception as _:
return False
if __name__ == '__main__':
print("{expression}: {validity}".format(expression="4.0 + 2", validity=check_valid("4.0 + 2")))
print("{expression}: {validity}".format(expression="3.88327 - $3.4", validity=check_valid("3.88327 - $3.4")))
print("{expression}: {validity}".format(expression="a + 24", validity=check_valid("a + 24")))
print("{expression}: {validity}".format(expression="2+6", validity=check_valid("2+6")))

How do I reverse words in a string with Python

I am trying to reverse words of a string, but having difficulty, any assistance will be appreciated:
S = " what is my name"
def reversStr(S):
for x in range(len(S)):
return S[::-1]
break
What I get now is: eman ym si tahw
However, I am trying to get: tahw is ym eman (individual words reversed)
def reverseStr(s):
return ' '.join([x[::-1] for x in s.split(' ')])
orig = "what is my name"
reverse = ""
for word in orig.split():
reverse = "{} {}".format(reverse, word[::-1])
print(reverse)
Since everyone else's covered the case where the punctuation moves, I'll cover the one where you don't want the punctuation to move.
import re
def reverse_words(sentence):
return re.sub(r'[a-zA-Z]+', lambda x : x.group()[::-1], sentence)
Breaking this down.
re is python's regex module, and re.sub is the function in that module that handles substitutions. It has three required parameters.
The first is the regex you're matching by. In this case, I'm using r'\w+'. The r denotes a raw string, [a-zA-Z] matches all letters, and + means "at least one".
The second is either a string to substitute in, or a function that takes in a re.MatchObject and outputs a string. I'm using a lambda (or nameless) function that simply outputs the matched string, reversed.
The third is the string you want to do a find in a replace in.
So "What is my name?" -> "tahW si ym eman?"
Addendum:
I considered a regex of r'\w+' initially, because better unicode support (if the right flags are given), but \w also includes numbers and underscores. Matching - might also be desired behavior: the regexes would be r'[a-zA-Z-]+' (note trailing hyphen) and r'[\w-]+' but then you'd probably want to not match double-dashes (ie --) so more regex modifications might be needed.
The built-in reversed outputs a reversed object, which you have to cast back to string, so I generally prefer the [::-1] option.
inplace refers to modifying the object without creating a copy. Yes, like many of us has already pointed out that python strings are immutable. So technically we cannot reverse a python string datatype object inplace. However, if you use a mutable datatype, say bytearray for storing the string characters, you can actually reverse it inplace
#slicing creates copy; implies not-inplace reversing
def rev(x):
return x[-1::-1]
# inplace reversing, if input is bytearray datatype
def rev_inplace(x: bytearray):
i = 0; j = len(x)-1
while i<j:
t = x[i]
x[i] = x[j]
x[j] = t
i += 1; j -= 1
return x
Input:
x = bytearray(b'some string to reverse')
rev_inplace(x)
Output:
bytearray(b'esrever ot gnirts emose')
Try splitting each word in the string into a list (see: https://docs.python.org/2/library/stdtypes.html#str.split).
Example:
>>string = "This will be split up"
>>string_list = string.split(" ")
>>string_list
>>['This', 'will', 'be', 'split', 'up']
Then iterate through the list and reverse each constituent list item (i.e. word) which you have working already.
def reverse_in_place(phrase):
res = []
phrase = phrase.split(" ")
for word in phrase:
word = word[::-1]
res.append(word)
res = " ".join(res)
return res
[thread has been closed, but IMO, not well answered]
the python string.lib doesn't include an in place str.reverse() method.
So use the built in reversed() function call to accomplish the same thing.
>>> S = " what is my name"
>>> ("").join(reversed(S))
'eman ym si tahw'
There is no obvious way of reversing a string "truly" in-place with Python. However, you can do something like:
def reverse_string_inplace(string):
w = len(string)-1
p = w
while True:
q = string[p]
string = ' ' + string + q
w -= 1
if w < 0:
break
return string[(p+1)*2:]
Hope this makes sense.
In Python, strings are immutable. This means you cannot change the string once you have created it. So in-place reverse is not possible.
There are many ways to reverse the string in python, but memory allocation is required for that reversed string.
print(' '.join(word[::-1] for word in string))
s1 = input("Enter a string with multiple words:")
print(f'Original:{s1}')
print(f'Reverse is:{s1[::-1]}')
each_word_new_list = []
s1_split = s1.split()
for i in range(0,len(s1_split)):
each_word_new_list.append(s1_split[i][::-1])
print(f'New Reverse as List:{each_word_new_list}')
each_word_new_string=' '.join(each_word_new_list)
print(f'New Reverse as String:{each_word_new_string}')
If the sentence contains multiple spaces then usage of split() function will cause trouble because you won't know then how many spaces you need to rejoin after you reverse each word in the sentence. Below snippet might help:
# Sentence having multiple spaces
given_str = "I know this country runs by mafia "
tmp = ""
tmp_list = []
for i in given_str:
if i != ' ':
tmp = tmp + i
else:
if tmp == "":
tmp_list.append(i)
else:
tmp_list.append(tmp)
tmp_list.append(i)
tmp = ""
print(tmp_list)
rev_list = []
for x in tmp_list:
rev = x[::-1]
rev_list.append(rev)
print(rev_list)
print(''.join(rev_list))
output:
def rev(a):
if a == "":
return ""
else:
z = rev(a[1:]) + a[0]
return z
Reverse string --> gnirts esreveR
def rev(k):
y = rev(k).split()
for i in range(len(y)-1,-1,-1):
print y[i],
-->esreveR gnirts

why am i getting error -Single '}' encountered in format string

I am writing some code to see print out a list of words that I can make with the string of letters 'myLetters', but for some reason my formatting wont work. It is supposed to come out as a list of words with as many spaces between it and the value as the length of myLetters + 4
def scrabbleWords(myLetters):
letterPoints = {'a':1,'b':3,'c':3,'d':2, 'e':1,'f':4,'g':2,'h':4,\
'i':1,'j':8,'k':5,'l':1,'m':3,'n':1,'o':1,'p':3,'q':10,'r':1,'s':1,\
't':1,'u':1,'v':4,'w':4,'x':8,'y':4}
wordList = createWordList('wordlist.txt')
myWords = []
for myWord in wordList:
x = canWeMakeIt(myWord,myLetters)
if x == True:
myWords.append(myWord)
pointWordList = []
for myWord in myWords:
t = getWordPoints(myWord,letterPoints)
pointWordList.append((t,myWord))
pointWordList.sort(reverse=True)
lenx = str(len(myLetters)+4)
for pointValue, myWord in pointWordList:
x = '{:'+lenx+'}{}'.format(myWord,pointValue)
print(x)
'{:'+lenx+'}{}'.format(myWord,pointValue)
interprets as
'{:' + lenx + '}{}'.format(myWord,pointValue)
Change it to:
'{1:{0}}{2}'.format(lenx, myWord, pointValue)
EDIT: don't forget to change lenx to an integer (or don't convert it to string at all):
lenx = len(myLetters) + 4
The problem is with the '{:'+lenx+'}{}'.format(myWord,pointValue) expression which tries to add lenx+'}{}'.format(myWord,pointValue) to the sum '{:'+lenx.
This would do what I think you want and be a little more readable in my opinion:
x = '{:{width}}{}'.format(myWord, pointValue, width=lenx)
EDIT: Plus this works whether lenx is an integer or string value.
The "Single '}' encountered in format string" error is due to the fact that we are looking at a bit of code that does not work without some bracketing.
You wrote
'{:'+lenx+'}{}'.format(myWord,pointValue)
but probably meant
('{:'+lenx+'}{}').format(myWord,pointValue)
whereas python's interpretation is:
'{:'+lenx+('}{}'.format(myWord,pointValue))

Categories