I'm trying to rewrite the equivalent of the python replace() function without using regexp. Using this code, i've managed to get it to work with single chars, but not with more than one character:
def Replacer(self, find_char, replace_char):
s = []
for char in self.base_string:
if char == find_char:
char = replace_char
#print char
s.append(char)
s = ''.join(s)
my_string.Replacer('a','E')
Anybody have any pointers how to make this work with more than one character? example:
my_string.Replacer('kl', 'lll')
How clever are you trying to be?
def Replacer(self, find, replace):
return(replace.join(self.split(find)))
>>> Replacer('adding to dingoes gives diamonds','di','omg')
'adomgng to omgngoes gives omgamonds'
Here is a method that should be pretty efficient:
def replacer(self, old, new):
return ''.join(self._replacer(old, new))
def _replacer(self, old, new):
oldlen = len(old)
i = 0
idx = self.base_string.find(old)
while idx != -1:
yield self.base_string[i:idx]
yield new
i = idx + oldlen
idx = self.base_string.find(old, i)
yield self.base_string[i:]
Let's try with some slices (but you really should consider using the builtin method of python) :
class ReplacableString:
def __init__(self, base_string):
self.base_string =base_string
def replacer(self, to_replace, replacer):
for i in xrange(len(self.base_string)):
if to_replace == self.base_string[i:i+len(to_replace)]:
self.base_string = self.base_string[:i] + replacer + self.base_string[i+len(to_replace):]
def __str__(self):
return str(self.base_string)
test_str = ReplacableString("This is eth string")
test_str.replacer("eth", "the")
print test_str
>>> This is the string
Related
I'm doing the valid palindrome problem at leetcode, below is the problem discription:
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
Example 1:
Input:
A man, a plan, a canal: Panama
Output:
true
Example 2:
Input:
race a car
Output:
false
Here is my code, my code was able to pass the first example A man, a plan, a canal: Panama, but failed the second one race a car. I have no idea why.
class Solution:
def isPalindrome(self, s: str) -> bool:
mystring = s.lower()
mystring2 = ""
for i in mystring:
if i.isalnum():
mystring2 += i
return mystring2
for i in range(0, int(len(mystring2)/2)):
if mystring2[i] != mystring2[len(mystring2)-i-1]:
return False
return True
You don't need to return mystring2 after your first loop ends. You can directly start with the second loop. Your logic seems to be correct. Just doing this modification would work.
Correct Code -
class Solution:
def isPalindrome(self, s: str) -> bool:
mystring = s.lower()
mystring2 = ""
for i in mystring:
if i.isalnum():
mystring2 += i
for i in range(0, int(len(mystring2)/2)):
if mystring2[i] != mystring2[len(mystring2)-i-1]:
return False
return True
In your case, it is failing because you are just returning from the function halfway through your code. The last loop part of code was never getting executed in your case.
Also, in python, the last part of the loop can be written in a much simpler way -
Slightly Simplified code -
class Solution:
def isPalindrome(self, s: str) -> bool:
mystring = s.lower()
mystring2 = ""
for i in mystring:
if i.isalnum():
mystring2 += i
return mystring2 == mystring2[::-1]
Similarly, you could also reduce the first part of your code as -
More Simplified Code -
class Solution:
def isPalindrome(self, s: str) -> bool:
mystring2 = ''.join([character.lower() for character in s if chracter.isalnum()])
return mystring2 == mystring2[::-1]
Easier way to do this is to reverse the string and compare in more pythonic way
a = "A man, a plan, a canal: Panama"
newA= [i.lower() for i in a if i.isalnum()]
print(newA == newA[::-1])
At last, you have to return true or false only, not the string.
class Solution:
def isPalindrome(self, s: str) -> bool:
mystring = s.lower()
mystring2 = ""
for i in mystring:
if i.isalnum():
mystring2 += i
return (mystring2 == mystring2[::-1])
Even though is not recommended, we can also solve this problem with a regular expression.
This'll pass:
class Solution:
def isPalindrome(self, s):
s = ''.join(re.findall(r'(?is)[a-z0-9]+', s)).lower()
return s == s[::-1]
Java
class Solution {
public boolean isPalindrome(String s) {
String original = s.replaceAll("(?i)[^a-z0-9]", "").toLowerCase();
String reversed = new StringBuffer(original).reverse().toString();
return original.equals(reversed);
}
}
JavaScript
var isPalindrome = function(s) {
var original = s.replace(/[^a-z0-9]/isg, '');
var reversed = original.split('').reverse().join('');
return original.toLowerCase() == reversed.toLowerCase();
};
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
I am working on a python Caesar cypher (for fun, I know it's not a good way to encrypt messages) and I ran into a problem. When I run the first bit of code, I get an error saying that the first arg in replace() must be a string, not an integer, when it is in face already a string ("TypeError: replace() argument 1 must be str, not int").
However, whenever I try to use it as an indice for a string, it tells me it is not an int ("TypeError: string indices must be integers").
Here is the code, thanks in advance. (There are a few more parts to the code but I don't think they're relevant to the question.)
def find_str(s, char):
index = 0
if char in s:
c = char[0]
for ch in s:
if ch == c:
if s[index:index+len(char)] == char:
return index
index += 1
return -1
class Alpha:
def __init__(self, message, key):
self.fKey = key
self.msg = str(message)
self.alpha = []
self.spcLoc = []
self.spcNum = 0
self.encryptedMessage = str(self.msg)
def encMsg(self):
for letter in self.spcNum):
str.replace(letter, find_str(self.alpha,letter) + self.fKey, self.spcNum)
def main():
msg = 'This is sparta'
key = 1
a = Alpha(msg, key)
a.encMsg()
for letter in self.spcNum:
This is a for-each loop which loops over every value in self.spcNum.
For example
for letter in ['a','b','c']:
print(letter)
will print out the letters a, b and c.
You can not iterate over self.spcNum. Because it is an integer (with the value 0) not a list.
There are other problems in the code too,
str.replace(letter, find_str(self.alpha,letter) + self.fKey, self.spcNum)
You're using this method incorrectly.
Correct usage:
stringYouWantEdited = "hi, my name is DGGB, hi"
substringYouWantReplaced = "hi"
newSubstring = "hello"
numberOfTimesThisShouldHappen = 1
newString = stringYouWantEdited.replace(substringYouWantReplaced , newSubstring , numberOfTimesThisShouldHappen )
print(newString)
I have a text file a.txt. I want to perform some preprocess on it like remove punct. and split it into words.
I have written the following code to perform few operations.
class pre:
def __init__(self,textfilepath):
self.textfilepath = textfilepath
def __str__(self,textfilepath):
return str(textfilepath)
def process(textpathfile):
with open(textpathfile, r) as abc:
a = abc.translate(string.maketrans("",""), string.punctuation)
a = a.split(' ')
return a
pre("a.txt")
I tried executing it.But it gave an error pre doesn't take arguments. Can any one help me with how to do this? Thanks all.
You shouldn't pass arguments to __str__. Instead you can access them through the properties of self:
class pre:
def __init__(self,textfilepath):
self.textfilepath = textfilepath
def __str__(self):
return self.textfilepath
def process(self):
with open(self.textfilepath, r) as abc:
a = abc.translate(string.maketrans("",""), string.punctuation)
a = a.split(' ')
return a
p = pre("a.txt")
print(p)
filedata = p.process()
print(filedata)
I'd like to create a regular expression in Python that will match against a line in Python source code and return a list of function calls.
The typical line would look like this:
something = a.b.method(time.time(), var=1) + q.y(x.m())
and the result should be:
["a.b.method()", "time.time()", "q.y()", "x.m()"]
I have two problems here:
creating the correct pattern
the catch groups are overlapping
thank you for help
I don't think regular expressions is the best approach here. Consider the ast module instead, for example:
class ParseCall(ast.NodeVisitor):
def __init__(self):
self.ls = []
def visit_Attribute(self, node):
ast.NodeVisitor.generic_visit(self, node)
self.ls.append(node.attr)
def visit_Name(self, node):
self.ls.append(node.id)
class FindFuncs(ast.NodeVisitor):
def visit_Call(self, node):
p = ParseCall()
p.visit(node.func)
print ".".join(p.ls)
ast.NodeVisitor.generic_visit(self, node)
code = 'something = a.b.method(foo() + xtime.time(), var=1) + q.y(x.m())'
tree = ast.parse(code)
FindFuncs().visit(tree)
result
a.b.method
foo
xtime.time
q.y
x.m
$ python3
>>> import re
>>> from itertools import chain
>>> def fun(s, r):
... t = re.sub(r'\([^()]+\)', '()', s)
... m = re.findall(r'[\w.]+\(\)', t)
... t = re.sub(r'[\w.]+\(\)', '', t)
... if m==r:
... return
... for i in chain(m, fun(t, m)):
... yield i
...
>>> list(fun('something = a.b.method(time.time(), var=1) + q.y(x.m())', []))
['time.time()', 'x.m()', 'a.b.method()', 'q.y()']
/([.a-zA-Z]+)\(/g
should match the method names; you'd have to add the parens after since you have some nested.
I don't really know Python, but I can imagine that making this work properly involves some complications, eg:
strings
comments
expressions that return an object
But for your example, an expression like this works:
(?:\w+\.)+\w+\(
I have an example for you proving this is doable in Python3
import re
def parse_func_with_params(inp):
func_params_limiter = ","
func_current_param = func_params_adder = "\s*([a-z-A-Z]+)\s*"
try:
func_name = "([a-z-A-Z]+)\s*"
p = re.compile(func_name + "\(" + func_current_param + "\)")
print(p.match(inp).groups())
except:
while 1:
func_current_param += func_params_limiter + func_params_adder
try:
func_name = "([a-z-A-Z]+)\s*"
p = re.compile(func_name + "\(" + func_current_param + "\)")
print(p.match(inp).groups())
break
except:
pass
Command line Input: animalFunc(lion, tiger, giraffe, singe)
Output: ('animalFunc', 'lion', 'tiger', 'giraffe', 'singe')
As you see the function name is always the first in the list and the rest are the paramaters names passed
So I'm fairly new to Python but I have absolutely no idea why this strong oldUser is changing to current user after I make the parse call. Any help would be greatly appreciated.
while a < 20:
f = urllib.urlopen("SITE")
a = a+1
for i, line in enumerate(f):
if i == 187:
print line
myparser.parse(line)
if fCheck == 1:
result = oldUser[0] is oldUser[1]
print oldUser[0]
print oldUser[1]
else:
result = user is oldUser
fCheck = 1
print result
user = myparser.get_descriptions(firstCheck)
firstCheck = 1
print user
if result:
print "SAME"
array[index+1] = array[index+1] +0
else:
oldUser = user
elif i > 200:
break
myparser.reset()
I don't understand why result doesn't work either... I print out both values and when they're the same it's telling me they're not equal... Also, why does myparser.parse(line) turn oldUser into a size 2 array? Thanks!
** Here's the definition for myparse...
class MyParser(sgmllib.SGMLParser):
"A simple parser class."
def parse(self, s):
"Parse the given string 's'."
self.feed(s)
self.close()
def __init__(self, verbose=0):
"Initialise an object, passing 'verbose' to the superclass."
sgmllib.SGMLParser.__init__(self, verbose)
self.divs = []
self.descriptions = []
self.inside_div_element = 0
def start_div(self, attributes):
"Process a hyperlink and its 'attributes'."
for name, value in attributes:
if name == "id":
self.divs.append(value)
self.inside_div_element = 1
def end_div(self):
"Record the end of a hyperlink."
self.inside_div_element = 0
def handle_data(self, data):
"Handle the textual 'data'."
if self.inside_div_element:
self.descriptions.append(data)
def get_div(self):
"Return the list of hyperlinks."
return self.divs
def get_descriptions(self, check):
"Return a list of descriptions."
if check == 1:
self.descriptions.pop(0)
return self.descriptions
Don’t compare strings with is. That checks if they’re the same object, not two copies of the same string. See:
>>> string = raw_input()
hello
>>> string is 'hello'
False
>>> string == 'hello'
True
Also, the definition of myparser would be useful.
I'm not quite sure what your code is doing, but I suspect you want to use == instead of is. Using is compares object identity, which is not the same as string equality. Two different string objects may contain the same sequence of characters.
result = oldUser[0] == oldUser[1]
If you're curious, for more information on the behaviour of the is operator see Python “is” operator behaves unexpectedly with integers.