Python use in the same line "For", "If" and "Else" - python

I want to learn python "secrets", it's possible to put all this code in one line?:
word_not_clean="Casà: 25$"
word_clean=""
for x in word_not_clean:
if x in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789':
word_clean+=x
else:
word_clean+='_'
This sentences work, but no replace especial characters:
word_clean="".join(x for x in word_not_clean if x in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
But this sentence with else doesn't works.
word_clean="".join(x for x in word_not_clean if x in 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' else '_')
Thank you in advance.

If you want to do it using list comprehension (one-lining lines) add the if-else statement before the for:
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
word_clean = "".join([x if x in chars else '_' for x in word_not_clean])

You can try like the below and also, you can use string.ascii_uppercase + string.ascii_lowercase + string.digits.
import string
word_not_clean="Casà: 25$"
chars_check = string.ascii_uppercase + string.ascii_lowercase + string.digits
result = ''.join(x if x in chars_check else '_' for x in word_not_clean)
print(result)
# 'Cas___25_'
Explanation:
>>> import string
>>> string.ascii_uppercase + string.ascii_lowercase + string.digits
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'

There are two different kinds of if statements in generator expressions. The first kind (which I’ll call an “inclusion if”) comes after the for statement, and indicates whether a given item from an iterator should be included in the resultant list. This is what you’re using in the first example.
The second kind (which I’ll call a “ternary if”) comes before the if statement, and used Python’s ternary operator __ if __ else __ to decide what should be outputted by the iterator. This is what you want for the second example, but you need to reorder your terms:
OKAY = “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789”
word_clean = "".join(
x if x in OKAY else '_' # Ternary if
for x in word_not_clean
)

Related

Python regex with number of occurences

Hi I'm looking for a regular expression that would allow me not only to replace characters but also to annotate the occurrence number.
For example I would like to replace all special characters with "s", all letters with "c" and all number with "d" and annotate their occurrence between "{}".
If I have "123-45AB-78!£", I would like to get d{3}s{1}d{3}c{2}s{1}d{2}s{2}.
Is there a way to do that with regex?
Many thanks
Here is one approach using re.sub with a callback function:
import re
def repl(m):
c = m.group()
if re.search(r'^[A-Za-z]+$', c):
return 'c{' + str(len(c.decode('utf8'))) + '}'
elif re.search(r'^\d+$', c):
return 'd{' + str(len(c.decode('utf8'))) + '}'
else:
return 's{' + str(len(c.decode('utf8'))) + '}'
x = "123-45AB-78!£"
print(re.sub('[A-Za-z]+|\d+|\D+', repl, x))
# d{3}s{1}d{2}c{2}s{1}d{2}s{2}
Note that since your input string contains non ASCII characters, we cannot simply use len() to find the numbes of characters in the string. Assuming a UTF-8 character set and a string str, we can use the following formula:
len(str.decode('utf8'))
Here is a method that first replaces each character by its type-character, then counts them with itertools.groupby. I'm not sure it is any faster than the good answer given by Tim, but it should be comparable.
x = "123-45AB-78!£"
for pat, sub in [(r"[A-Za-z]", "c"), (r"\d", "d"), (r"[^\d\w]", "s")]:
x = re.sub(pat, sub, x)
print(x) # dddsddccsddss
y = "".join([f"{k}{{{len(list(g))}}}" for k, g in groupby(x)])
print(y) # d{3}s{1}d{2}c{2}s{1}d{2}s{2}

Replace substring of given indices range

I am new in Python programming. I am stuck at one point. Let's say I have string "hello-world". I want to replace all the characters of this string with "*" except first & last. so the result will be "h***-****d".
One way to do this as below:
In [1]: s = "hello-world"
In [2]: s[0] + "*"*(len(s)-2) + s[-1]
Out[2]: 'h*********d'
If I want to replace all characters with "*" except first & last 2 characters
In [3]: s[:2] + "*"*(len(s)-4) + s[-2:]
Out[3]: 'he*******ld'
Is there any pretty way to handle these type of problems. Any help would be appreciated. Thanks.
I think what you want to do is this:
def obscure(string, n):
characters = list(string)
characters[n:-n] = '*' * len(characters[n:-n])
obscured = ''.join(characters)
return obscured
Turn the string into a list of characters. Replace the ones you want to obscure. Then join the list back into a string.
You can use str.join (and the string module to check against letters):
s[0] + ''.join(['*' if i in string.ascii_letters else i
for i in s[1:-1]]) + s[-1]
Since you said you wanted h****-****d where the hyphen isn't replaced, you would need to test whether the characters are letters or not. You could change string.ascii_letters to:
chars = 'abcdefghijklmnopqrstuvwxyz'
chars = chars + chars.upper() + '0123456789' # + 'some_other_chars'
...if you want to include other characters like numbers or punctuation. Or you can write out the letters you want to replace manually.
You may also want to perform a check to see whether the string is 3 characters or more so that no errors are raised.
You could define a function to not repeat yourself:
def replace(s, n):
if len(s) > n*2:
return s[:n] + '*'*(len(s)-n*2) + s[-n:]
return s
print(replace('hello-world', 1)) # h*********d
print(replace('hello-world', 2)) # he*******ld
print(replace('hello', 2)) # he*lo
print(replace('hello', 3)) # hello
You can also use some kind of string formatting instead of concatenation (which should be more efficient), e.g. f-strings available in 3.6+:
def replace(s, n):
if len(s) > n*2:
return f"{ s[:n] }{ '*'*(len(s)-n*2) }{ s[-n:] }"
return s
You can try this.
s="hello-world"
for i in s[1:-1]:
if i.isalpha():
s=s.replace(i,"*")

Surround strings in a list with a certain character

I have a list consisting of strings and I need to surround each of the strings with asterisks. With the input:
def addAsterisks(["abc", "ded"])
The output should be:
["*abc*", "*ded*"]
Here is what I have tried:
for x in strs:
x = "*" + x + "*"
However, the output is unchanged:
["abc", "ded"]
x is a local variable, so changing it is meaningless once it goes out of scope. You could, e.g., return the modified list and assign it somewhere:
def addAsterisks(l)
return ['*' + x + '*' for x in l]
myList = addAsterisks(["abc", "ded"])
You can use, also, str.format():
def addAsterisks(a):
# Or:
# return ["*%s*" %k for k in a]
return ["*{}*".format(k) for k in a]
print(addAsterisks(["abc", "ded"]))
>>> ['*abc*', '*ded*
You have to modify the list to reflect changes in your list. I used inline function for compact code.
Code
['*'+ i + "*" for picture in pictures]
input
["abc", "def"]
Output
["*abc*", "*def*"]
Modify the the array and return to where you want to use. Modifying a temp variable (x) wont work since u will loose it once you are out of scope.
def addAsterisks(string_list):
return ['*' + x + '*' for x in string_list]
print addAsterisks(["abc", "ded"])
This will output:
['*abc*', '*ded*']
You are assigning to a temporary variable x, which does not change the actual list. Try instead
return ["*" + x + "*" for x in picture]
or, if you want a loop:
for i,x in enumerate(picture):
picture[i] = "*" + x + "*"
You can also do like this:
In [22]: def addAsterisks(s):
...: newarr = []
...: for i in s:
...: newstr = "*" + str(i) + "*"
...: newarr.append(newstr)
...: print(newarr)
...:
In [23]: addAsterisks(["abc", "ded"])
['*abc*', '*ded*']
Here is the Pythonic way of tackling this question:
A = [ "*"+a+"*" for a in picture ]
Hint: Read about list comprehension in Python.
I'm late at the party.
Other solutions are better for the specific use case, but this might help someone else (it is a totally different approach from other answers).
If you are really sure about the length of each string to be exactly three, you can do the following:
def addAsterisks(items):
return [ f'{value:*^5}' for value in items ]
addAsterisks(["abc","def"])
Please note that if you change 5 to 7 you will surrond each string with 2 asterisks

Python - making a function that would add "-" between letters

I'm trying to make a function, f(x), that would add a "-" between each letter:
For example:
f("James")
should output as:
J-a-m-e-s-
I would love it if you could use simple python functions as I am new to programming. Thanks in advance. Also, please use the "for" function because it is what I'm trying to learn.
Edit:
yes, I do want the "-" after the "s".
Can I try like this:
>>> def f(n):
... return '-'.join(n)
...
>>> f('james')
'j-a-m-e-s'
>>>
Not really sure if you require the last 'hyphen'.
Edit:
Even if you want suffixed '-', then can do like
def f(n):
return '-'.join(n) + '-'
As being learner, it is important to understand for your that "better to concat more than two strings in python" would be using str.join(iterable), whereas + operator is fine to append one string with another.
Please read following posts to explore further:
Any reason not to use + to concatenate two strings?
which is better to concat string in python?
How slow is Python's string concatenation vs. str.join?
Also, please use the "for" function because it is what I'm trying to learn
>>> def f(s):
m = s[0]
for i in s[1:]:
m += '-' + i
return m
>>> f("James")
'J-a-m-e-s'
m = s[0] character at the index 0 is assigned to the variable m
for i in s[1:]: iterate from the second character and
m += '-' + i append - + char to the variable m
Finally return the value of variable m
If you want - at the last then you could do like this.
>>> def f(s):
m = ""
for i in s:
m += i + '-'
return m
>>> f("James")
'J-a-m-e-s-'
text_list = [c+"-" for c in text]
text_strung = "".join(text_list)
As a function, takes a string as input.
def dashify(input):
output = ""
for ch in input:
output = output + ch + "-"
return output
Given you asked for a solution that uses for and a final -, simply iterate over the message and add the character and '-' to an intermediate list, then join it up. This avoids the use of string concatenations:
>>> def f(message)
l = []
for c in message:
l.append(c)
l.append('-')
return "".join(l)
>>> print(f('James'))
J-a-m-e-s-
I'm sorry, but I just have to take Alexander Ravikovich's answer a step further:
f = lambda text: "".join([c+"-" for c in text])
print(f('James')) # J-a-m-e-s-
It is never too early to learn about list comprehension.
"".join(a_list) is self-explanatory: glueing elements of a list together with a string (empty string in this example).
lambda... well that's just a way to define a function in a line. Think
square = lambda x: x**2
square(2) # returns 4
square(3) # returns 9
Python is fun, it's not {enter-a-boring-programming-language-here}.

Analyzing string input until it reaches a certain letter on Python

I need help in trying to write a certain part of a program.
The idea is that a person would input a bunch of gibberish and the program will read it till it reaches an "!" (exclamation mark) so for example:
input("Type something: ")
Person types: wolfdo65gtornado!salmontiger223
If I ask the program to print the input it should only print wolfdo65gtornado and cut anything once it reaches the "!" The rest of the program is analyzing and counting the letters, but those part I already know how to do. I just need help with the first part. I been trying to look through the book but it seems I'm missing something.
I'm thinking, maybe utilizing a for loop and then placing restriction on it but I can't figure out how to make the random imputed string input be analyzed for a certain character and then get rid of the rest.
If you could help, I'll truly appreciate it. Thanks!
The built-in str.partition() method will do this for you. Unlike str.split() it won't bother to cut the rest of the str into different strs.
text = raw_input("Type something:")
left_text = text.partition("!")[0]
Explanation
str.partition() returns a 3-tuple containing the beginning, separator, and end of the string. The [0] gets the first item which is all you want in this case. Eg.:
"wolfdo65gtornado!salmontiger223".partition("!")
returns
('wolfdo65gtornado', '!', 'salmontiger223')
>>> s = "wolfdo65gtornado!salmontiger223"
>>> s.split('!')[0]
'wolfdo65gtornado'
>>> s = "wolfdo65gtornadosalmontiger223"
>>> s.split('!')[0]
'wolfdo65gtornadosalmontiger223'
if it doesnt encounter a "!" character, it will just grab the entire text though. if you would like to output an error if it doesn't match any "!" you can just do like this:
s = "something!something"
if "!" in s:
print "there is a '!' character in the context"
else:
print "blah, you aren't using it right :("
You want itertools.takewhile().
>>> s = "wolfdo65gtornado!salmontiger223"
>>> '-'.join(itertools.takewhile(lambda x: x != '!', s))
'w-o-l-f-d-o-6-5-g-t-o-r-n-a-d-o'
>>> s = "wolfdo65gtornado!salmontiger223!cvhegjkh54bgve8r7tg"
>>> i = iter(s)
>>> '-'.join(itertools.takewhile(lambda x: x != '!', i))
'w-o-l-f-d-o-6-5-g-t-o-r-n-a-d-o'
>>> '-'.join(itertools.takewhile(lambda x: x != '!', i))
's-a-l-m-o-n-t-i-g-e-r-2-2-3'
>>> '-'.join(itertools.takewhile(lambda x: x != '!', i))
'c-v-h-e-g-j-k-h-5-4-b-g-v-e-8-r-7-t-g'
Try this:
s = "wolfdo65gtornado!salmontiger223"
m = s.index('!')
l = s[:m]
To explain accepted answer.
Splitting
partition() function splits string in list with 3 elements:
mystring = "123splitABC"
x = mystring.partition("split")
print(x)
will give:
('123', 'split', 'ABC')
Access them like list elements:
print (x[0]) ==> 123
print (x[1]) ==> split
print (x[2]) ==> ABC
Suppose we have:
s = "wolfdo65gtornado!salmontiger223" + some_other_string
s.partition("!")[0] and s.split("!")[0] are both a problem if some_other_string contains a million strings, each a million characters long, separated by exclamation marks. I recommend the following instead. It's much more efficient.
import itertools as itts
get_start_of_string = lambda stryng, last, *, itts=itts:\
str(itts.takewhile(lambda ch: ch != last, stryng))
###########################################################
s = "wolfdo65gtornado!salmontiger223"
start_of_string = get_start_of_string(s, "!")
Why the itts=itts
Inside of the body of a function, such as get_start_of_string, itts is global.
itts is evaluated when the function is called, not when the function is defined.
Consider the following example:
color = "white"
get_fleece_color = lambda shoop: shoop + ", whose fleece was as " + color + " as snow."
print(get_fleece_color("Igor"))
# [... many lines of code later...]
color = "pink polka-dotted"
print(get_fleece_color("Igor's cousin, 3 times removed"))
The output is:
Igor, whose fleece was white as snow.
Igor's cousin, 3 times removed Igor, whose fleece was as pink polka-dotted as snow.
You can extract the beginning of a string, up until the first delimiter is encountered, by using regular expressions.
import re
slash_if_special = lambda ch:\
"\\" if ch in "\\^$.|?*+()[{" else ""
prefix_slash_if_special = lambda ch, *, _slash=slash_if_special: \
_slash(ch) + ch
make_pattern_from_char = lambda ch, *, c=prefix_slash_if_special:\
"^([^" + c(ch) + "]*)"
def get_string_up_untill(x_stryng, x_ch):
i_stryng = str(x_stryng)
i_ch = str(x_ch)
assert(len(i_ch) == 1)
pattern = make_pattern_from_char(ch)
m = re.match(pattern, x_stryng)
return m.groups()[0]
An example of the code above being used:
s = "wolfdo65gtornado!salmontiger223"
result = get_string_up_untill(s, "!")
print(result)
# wolfdo65gtornado
We can use itertools
s = "wolfdo65gtornado!salmontiger223"
result = "".join(itertools.takewhile(lambda x : x!='!' , s))
>>"wolfdo65gtornado"

Categories

Resources