How to escape string for generated C++? - python

I am writing python script which is generating C++ code based on the data.
I have python variable string which contains a string which can be composed
of characters like " or newlines.
What is the best way to escape this string for code generation?

The way I use is based on the observation that C++ strings basically
obey the same rules regarding charactes and escaping as Javascript/JSON string.
Python since version 2.6 has a built-in JSON library which can serialize Python
data into JSON. Therefore, the code is, assuming we don't need enclosing
quotes, just as follows:
import json
string_for_printing = json.dumps(original_string).strip('"')

I use this code, so far without problems:
def string(s, encoding='ascii'):
if isinstance(s, unicode):
s = s.encode(encoding)
result = ''
for c in s:
if not (32 <= ord(c) < 127) or c in ('\\', '"'):
result += '\\%03o' % ord(c)
else:
result += c
return '"' + result + '"'
It uses octal escapes to avoid all potentially problematic characters.

We can do better using specifics of C found here (https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#Character-Constants) and Python's built-in printable function:
def c_escape():
import string
mp = []
for c in range(256):
if c == ord('\\'): mp.append("\\\\")
elif c == ord('?'): mp.append("\\?")
elif c == ord('\''): mp.append("\\'")
elif c == ord('"'): mp.append("\\\"")
elif c == ord('\a'): mp.append("\\a")
elif c == ord('\b'): mp.append("\\b")
elif c == ord('\f'): mp.append("\\f")
elif c == ord('\n'): mp.append("\\n")
elif c == ord('\r'): mp.append("\\r")
elif c == ord('\t'): mp.append("\\t")
elif c == ord('\v'): mp.append("\\v")
elif chr(c) in string.printable: mp.append(chr(c))
else:
x = "\\%03o" % c
mp.append(x if c>=64 else (("\\%%0%do" % (1+c>=8)) % c, x))
return mp
This has the advantage of now being a mapping from ordinal value of a character ord(c) to the exact string. Using += for strings is slow and bad practice, so this allows for "".join(...) which is far more performant in Python. Not to mention, indexing a list/table is much faster than doing computations on characters each time through. Also do not waste octal characters either by checking if less characters are needed. However, to use this, you must verify the next character is not a 0 through 7 otherwise you must use the 3 digit octal format.
The table looks like:
[('\\0', '\\000'), ('\\1', '\\001'), ('\\2', '\\002'), ('\\3', '\\003'), ('\\4', '\\004'), ('\\5', '\\005'), ('\\6', '\\006'), '\\a', '\\b', '\\t', '\\n', '\\v', '\\f', '\\r', ('\\16', '\\016'), ('\\17', '\\017'), ('\\20', '\\020'), ('\\21', '\\021'), ('\\22', '\\022'), ('\\23', '\\023'), ('\\24', '\\024'), ('\\25', '\\025'), ('\\26', '\\026'), ('\\27', '\\027'), ('\\30', '\\030'), ('\\31', '\\031'), ('\\32', '\\032'), ('\\33', '\\033'), ('\\34', '\\034'), ('\\35', '\\035'), ('\\36', '\\036'), ('\\37', '\\037'), ' ', '!', '\\"', '#', '$', '%', '&', "\\'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '\\?', '#', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\\177', '\\200', '\\201', '\\202', '\\203', '\\204', '\\205', '\\206', '\\207', '\\210', '\\211', '\\212', '\\213', '\\214', '\\215', '\\216', '\\217', '\\220', '\\221', '\\222', '\\223', '\\224', '\\225', '\\226', '\\227', '\\230', '\\231', '\\232', '\\233', '\\234', '\\235', '\\236', '\\237', '\\240', '\\241', '\\242', '\\243', '\\244', '\\245', '\\246', '\\247', '\\250', '\\251', '\\252', '\\253', '\\254', '\\255', '\\256', '\\257', '\\260', '\\261', '\\262', '\\263', '\\264', '\\265', '\\266', '\\267', '\\270', '\\271', '\\272', '\\273', '\\274', '\\275', '\\276', '\\277', '\\300', '\\301', '\\302', '\\303', '\\304', '\\305', '\\306', '\\307', '\\310', '\\311', '\\312', '\\313', '\\314', '\\315', '\\316', '\\317', '\\320', '\\321', '\\322', '\\323', '\\324', '\\325', '\\326', '\\327', '\\330', '\\331', '\\332', '\\333', '\\334', '\\335', '\\336', '\\337', '\\340', '\\341', '\\342', '\\343', '\\344', '\\345', '\\346', '\\347', '\\350', '\\351', '\\352', '\\353', '\\354', '\\355', '\\356', '\\357', '\\360', '\\361', '\\362', '\\363', '\\364', '\\365', '\\366', '\\367', '\\370', '\\371', '\\372', '\\373', '\\374', '\\375', '\\376', '\\377']
Example usage encoding some 4-byte integers as C-strings in little-endian byte order with new lines inserted every 50 characters:
v
mp = c_escape()
vals = [30,50,100]
bytearr = [z for i, x in enumerate(vals) for z in x.to_bytes(4, 'little', signed=x<0)]
"".join(mp[x] if not type(mp[x]) is tuple else mp[x][1 if not i == len(bytearr)-1 and bytearr[i+1] in list(range(ord('0'), ord('7')+1)) else 0] + ("\"\n\t\"" if (i % 50) == 49 else "") for i, x in enumerate(bytearr))
#output: '\\36\\0\\0\\0002\\0\\0\\0d\\0\\0\\0'

Related

Trying to convert user define function result into list in python

#Password Generator Project
import random
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
print("Welcome to the PyPassword Generator!")
nr_letters= int(input("How many letters would you like in your password?\n"))
nr_symbols = int(input(f"How many symbols would you like?\n"))
nr_numbers = int(input(f"How many numbers would you like?\n"))
#Eazy Level - Order not randomised:
#e.g. 4 letter, 2 symbol, 2 number = JduE&!91
def my_function():
for i in range(1,nr_letters+1):
variable=random.choice(letters)
print(variable, end='')
for j in range(1,nr_symbols+1):
variable1=random.choice(symbols)
print(variable1, end='')
for k in range(1,nr_numbers+1):
variable2=random.choice(numbers)
print(variable2, end='')
#Hard Level - Order of characters randomised:
#e.g. 4 letter, 2 symbol, 2 number = g^2jk8&P
#my_function()
function_to_list=my_function()
print[(function_to_list)]
shuffle_my_function=random.shuffle(function_to_list)
print(shuffle_my_function)
This is a kind of personal project here my task is to generate a password. On the easy level just print the password sequence wise whereas on the hard level I want my password to be shuffled.
My easy level code is working perfectly but on the hard level, I want to shuffle the result of the easy level for that I thought that if I define a function of the easy part and then somehow convert that function into the list I can easily use shuffle function . so please help me. please try to do give a solution in my way of thinking and then please suggest your way of doing it
This is a common beginner problem. When you print something, it's there on the screen, but only as text. And the program can't see that text. You have to do something to the variables to keep track of them as you go. In this case, you need to append them to a list. Not only that, but you need to return the list to the caller, so that function_to_list = my_function() assigns something other than None to function_to_list:
def my_function():
list_of_characters = []
for i in range(nr_letters):
list_of_characters.append(random.choice(letters))
for j in range(nr_symbols):
list_of_characters.append(random.choice(symbols))
for k in range(nr_numbers):
list_of_characters.append(random.choice(numbers))
return list_of_characters
Notice that I took out the print statements. That's because a function should do only one thing and do it well. You can print your list and your password as soon as you get them back:
list_from_function = my_function()
print(list_from_function)
To print the list as a single string, join the letters it contains with the emtpy string:
print(''.join(list_from_function))
You can shuffle the result, or do whatever you want:
random.shuffle(list_from_function)
print(list_from_function)
Keep in mind that shuffle operates in place and returns None. That means that if you try to print its return value, you get nothing.
You don't need to use for loop. You can pass argument to random.choices() indicating how many items you want.
import random
import string
letters = string.ascii_letters
numbers = string.digits
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
# For demo, I hardcoded the numbers
nr_letters = 4
nr_symbols = 5
nr_numbers = 3
# create a list from randomly choosen characters
password_characters = random.choices(letters, k = nr_letters) \
+ random.choices(symbols, k = nr_symbols) \
+ random.choices(numbers, k = nr_numbers)
# shuffle the list:
random.shuffle(password_characters)
# convert the list to string
password = ''.join(password_characters)
Output:
>>> print(password)
>>> &J0*4oR!I3$!

How to encode a text string into a number in Python?

Let's say you have a string:
mystring = "Welcome to the InterStar cafe, serving you since 2412!"
I am looking for a way to convert that string into a number, like say:
encoded_string = number_encode(mystring)
print(encoded_string)
08713091353153848093820430298
..that you can convert back to the original string.
decoded_string = number_decode(encoded_string)
print(decoded_string)
"Welcome to the InterStar cafe, serving you since 2412!"
It doesn't have to be cryptographically secure, but it does have to put out the same number for the same string regardless of what computer it's running on.
encode it to a bytes in a fixed encoding, then convert the bytes to an int with int.from_bytes. The reverse operation is to call .to_bytes on the resulting int, then decode back to str:
mystring = "Welcome to the InterStar cafe, serving you since 2412!"
mybytes = mystring.encode('utf-8')
myint = int.from_bytes(mybytes, 'little')
print(myint)
recoveredbytes = myint.to_bytes((myint.bit_length() + 7) // 8, 'little')
recoveredstring = recoveredbytes.decode('utf-8')
print(recoveredstring)
Try it online!
This has one flaw, which is that if the string ends in NUL characters ('\0'/\x00') you'll lose them (switching to 'big' byte order would lose them from the front). If that's a problem, you can always just pad with a '\x01' explicitly and remove it on the decode side so there are no trailing 0s to lose:
mystring = "Welcome to the InterStar cafe, serving you since 2412!"
mybytes = mystring.encode('utf-8') + b'\x01' # Pad with 1 to preserve trailing zeroes
myint = int.from_bytes(mybytes, 'little')
print(myint)
recoveredbytes = myint.to_bytes((myint.bit_length() + 7) // 8, 'little')
recoveredstring = recoveredbytes[:-1].decode('utf-8') # Strip pad before decoding
print(recoveredstring)
If you are simply looking for making a certain string unreadable by a human you might use base64, base64.b64encode(s, altchars=None) and base64.b64decode(s, altchars=None, validate=False):
Take into account that it requires bytes-like object, so you should start your strings with b"I am a bytes-like string":
>>> import base64
>>> coded = base64.b64encode(b"Welcome to the InterStar cafe, serving you since 2412!")
>>> print(coded)
b'V2VsY29tZSB0byB0aGUgSW50ZXJTdGFyIGNhZmUsIHNlcnZpbmcgeW91IHNpbmNlIDI0MTIh'
>>> print(base64.b64decode(coded))
b"Welcome to the InterStar cafe, serving you since 2412!"
If you already have your strings, you can convert them with str.encode('utf-8'):
>>> myString = "Welcome to the InterStar cafe, serving you since 2412!"
>>> bString = myString.encode('utf-8')
>>> print(bString)
b'Welcome to the InterStar cafe, serving you since 2412!'
>>> print(bString.decode())
'Welcome to the InterStar cafe, serving you since 2412!'
If you really need to convert the string to only numbers, you would have to use #ShadowRanger's answer.
I think the other answers are better than this one, but purely mathematically, there is an obvious way of doing this. You just have to interpret a message as an integer written in another base system with different symbols
def frombase(s, sym):
b = len(sym)
n = 0
bl = 1
for a in reversed(s):
n += sym.index(a) * bl
bl *= b
return n
def tobase(n, sym):
b = len(sym)
s = ''
while n > 0:
kl = n % b
n //= b
s += sym[kl]
return s[::-1] if s else sym[0]
and then for your specific case
symbols = [
' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', ',', '.', '?', '!', '-', ':', ';',
'_', '"', "'", '#', '$', '%', '&', '/', '(', ')',
'=', '+', '*', '<', '>', '~'
]
encodeword = lambda w: frombase(w, symbols)
decodeword = lambda n: tobase(n, symbols)
Though the first symbol (" ") will be omitted if there's nothing in front of it, similarly to 0001 = 1.
If you really want to represent all possible symbols, you can write them as a sequence of their ord values (integers), seperated by the , symbol. Then you encode that in the base with an added , symbol:
symbols = [',', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] # , is zero
txt2int = lambda w: encodeword(','.join(str(ord(x)) for x in w))
int2txt = lambda n: ''.join(chr(int(x)) for x in decodeword(n).split(','))
Regarding the size of the returned integer: txt2int(w) = encodeword(w) = O(len(w)), meaning e.g. 'Hi there!' would encode to a number with about 9 digits.

Why does the pattern occurs, while using a set to create a random string?

I wrote a little function that will create a random string of a certain length:
def append_until_length(acceptable, length=45):
retval = set()
for _ in range(1000):
retval.add(random.choice(acceptable))
if len(retval) == length:
return ''.join(retval)
This works and everything, so it's all fine and dandy. But while running it I've noticed a sort of pattern if you will:
>>> for _ in range(10):
... append_until_length(acceptable)
...
'!#"%\'(+*-,/.057698=?ADGIHLRUV[]\\`behjmonpryx~'
'"$\')+*,025498:=?ACBGKONQPSY[]\\acdgfhkmruvy{z|'
'#"\'&)+,/03248=<?>ABFHJLOPWYXZ]cbdfhklonqrutz}'
' #"(*-/0328EIJMPSRUWVYX]_^acbegfkmlqpstwvx{}|'
'!#"(,/.032549;=>EDHMLOSYX[]_^acbedjlonprtvxz~'
" %',10346?#CEDFIKNQRVYXZ]\\_abghkjlnqpruw{z}|~"
'! #+,/035469:<#CFIKLSRUVY[Z^cbfijloqsutwvxz}|'
'$&)(+-/5;:?>ABDFIHMLOPSUTYXZa`bdhkjmonprwvx}~'
'!#"&*-/102579:=>#DFKJMLONQSTVYX\\^acimoqpstw}~'
'! &(+-/.2548:=<?A#EGFIKOQPSRTVX\\eihjonprutx}~'
>>>
If you look at this, the first few characters are always punctuation, the next few are always numbers, then comes the uppercase with some mixed punctuation, another punctuation, lowercase letters, and the last characters are always punctuation.
The acceptable characters I'm using are list(string.printable)[:-6] with a .append(" "). The length of this list is 95:
>>> acceptable
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '#', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~', ' ']
>>> len(acceptable)
95
>>>
Now I understand that the set() will not allow multiple of the same characters to be in the string, however, that does not explain the pattern always being the same (not really the same but remotely the same). See if I do this via a list there is never a pattern to the function:
>>> def append_until_length(acceptable, length=45):
... retval = []
... for _ in range(length):
... retval.append(random.choice(acceptable))
... return ''.join(retval)
...
>>> for _ in range(10):
... append_until_length(acceptable)
...
"] *rZI/<=LwPGU-PzWj)\\jp9tZ}e9T#}4/\\R`4Q^?4)'W"
'%z6wTvuzK;{eS}"^GRf(}a3<"Qqg_*2v?1`y#;=Bn#ycQ'
"t'bqj,*}7:w]:8c;Ddy. 17#^Y0{)>}'25tsl1kf+C%6^"
'RZt)s=?~QrAok+Z\\ei}5K^&1e+w0~*zl{hS2;l]|?p/T;'
'%InO5_fWcJU#v,6_=cPb^cfd1=\\;k{37~$214vd+F&oH&'
'!6Ey#"\'3.,ivG+7\'y[&1`aYNDg-\\j#:! -7(8b#$x)Q1m'
'w}/{mnT\\-IT2?;V_K ZDDy:YzaG+LgGkZWkV8E y#_)Y;'
'e1#71AFDF;|Q.<_fRG0tG*`557z(|}bHDCT+dc}{[QGq8'
"ie~;Iy1O)f!n,Z%%0\\36-!Lke1}cA'uptRS7(2ki|mzgi"
'G=v&#.J1#E$N?NK|~>( E4M/^y[~HK)#Hi$23ez~EY>N '
Even if I treat the list like a set there is still no pattern to the output strings:
def append_until_length(acceptable, length=45):
retval = []
for _ in range(10000):
char = random.choice(acceptable)
if char not in retval:
retval.append(char)
if len(retval) == length:
return ''.join(retval)
8hKO W5"'ERJa/N$vb9^4!)fig:c_n&?#(#}oTC]qePwZ
,b2;Y^VD9|:O!>QilH`4(7/F?8f&5~_B$x#pN{Igahs\n
_z1eDiH$9k&rRt>M/FOqb8SLY.{|0dI4A^:l,3cs7ng][
Y/iu#eOlVMmZ 9S`t?1JX2$<)&|jUz'"~wLIvoqkr}!(H
r~/m{8SLvU?_aVX4A"0%zEgK1I!9#B|snphOZb,#jw\]2
;nX!T20.^b"\eqNExOlrQF'V&#(%iht{Hw+-Sy,Dj]:9[
B#%H[2f&JuwSd1bEnih#}]3jTMLzAW.ZG~,tX|!/N_`D(
usv}KkZgL]&<hY^6Blp\GENTrFC~Xw3#4S8QmRf"PUnM|
?G3Ao[z7gVLve-}S>X]&<+k(DZ*UcsM50r)^1Om`P4K,6
,#&(1-'sj9qy7~dZpuIk!%Q D8haSNrco{xe;=.T[WK0<
So my question would be, why does the pattern occur with a set? The uppercase and lowercase characters have a different ord number, therefore are different characters. IE:
>>> ord("c")
99
>>> ord("C")
67
>>>
So in my head, it doesn't make sense to why there is a pattern in the strings, if they are randomly generated? According to help(set):
class set(object)
| set() -> new empty set object
| set(iterable) -> new set object
|
| Build an unordered collection of unique elements.
Your issue is that sets aren't really unordered. They obey to an implementation defined order that you cannot rely on or predict (and which is different between 2 executions of the python interpreter), but it's there ('order' of unordered Python sets).
In that case, it seems to be the natural alphabetical order but not necessarily:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> set("ABCDEFG")
{'A', 'E', 'F', 'G', 'C', 'B', 'D'}
>>> set("ABCDEFG")
{'A', 'E', 'F', 'G', 'C', 'B', 'D'}
Same order for 2 different sets, not alphabetical. Now let's run it again:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AM D64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> set("ABCDEFG")
{'C', 'G', 'D', 'B', 'E', 'A', 'F'}
>>>
different order (related to hash seed & python security features)
So, within the same instance of the interpreter, it sorts the different character kinds the same, which creates a "pattern".
To benefit from the speed of set (O(1) average lookup vs O(n) for lists) and keep the chaotic order that random provided, you could use an auxiliary set to test, but store in a list:
def append_until_length(acceptable, length=45):
retval = []
testset = set()
for _ in range(10000):
char = random.choice(acceptable)
if char not in testset: # fast lookup (O(1))
retval.append(char) # add to the result list
testset.add(char) # add to the set
if len(retval) == length:
return ''.join(retval)

Python Password Generator

I am trying to create a password generator in Python that must contain an uppercase letter, lowercase letter, and a number, and must have a length between 6 and 20 characters.
import random
import string
def password_gen():
while True:
length = random.randint(6,20)
pwd = []
for i in range(length):
prob = random.random()
if prob < 0.34:
char = random.choice(string.ascii_lowercase)
pwd.append(char)
elif prob < 0.67:
char = random.choice(string.ascii_uppercase)
pwd.append(char)
else:
char = str(random.randint(0,9))
pwd.append(char)
pwd = ''.join(pwd)
#check password here
return pwd
However, I am having trouble checking the password to make sure it contains the required characters listed earlier. I am not sure if/how i would use a continue statement.Any help would be greatly appreciated!
I think this would be a bit easier to ensure you meet the base requirements if you just handle those upfront.
import random
import string
def generate_pw():
length = random.randint(6,20) - 3
pwd = []
pwd.append(random.choice(string.ascii_lowercase))
pwd.append(random.choice(string.ascii_uppercase))
pwd.append(str(random.randint(0,9)))
# fill out the rest of the characters
# using whatever algorithm you want
# for the next "length" characters
random.shuffle(pwd)
return ''.join(pwd)
This will ensure your password has the characters you need. For the rest of the characters you could for example just use a list of all alphanumeric characters and call random.choice length times.
you can use isupper() and islower() functions to get does your password contain uppercase and lowercase.
e.g.
upper=0
lower=0
for i in range(length):
if (pwd[i].islower()):
upper=1
elif (pwd[i].isupper()):
lower=1
import random
import string
def password_gen():
lower_case_letter = random.choice(string.ascii_lowercase)
upper_case_letter = random.choice(string.ascii_uppercase)
number = random.choice(string.digits)
other_characters = [
random.choice(string.ascii_letters + string.digits)
for index in range(random.randint(3, 17))
]
all_together = [lower_case_letter, upper_case_letter] + other_characters
random.shuffle(all_together)
return ''.join(all_together)
Password Generator more broken down, you can get any number you wish, but it outputs a pattern by first adding letters, then numbers and finally symbols
import random
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
numbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
symbols = ['!', '#', '$', '%', '&', '(', ')', '*', '+']
print("Welcome to the PyPassword Generator!")
nr_letters= int(input("How many letters would you like in your password?\n"))
nr_symbols = int(input(f"How many symbols would you like?\n"))
nr_numbers = int(input(f"How many numbers would you like?\n"))
passwordlength = nr_letters + nr_numbers + nr_symbols
chars = ""
for x in range (0, nr_letters):
char = random.choice(letters)
chars += char
nums = ""
for y in range (0, nr_numbers):
num = random.choice(numbers)
nums+=num
syms = "" # string accumulator
for z in range (0, nr_symbols):
symb = random.choice(symbols)
syms += symb
print(f"Here is your password: {chars}{nums}{syms}")

Morse code decoder python function [duplicate]

This question already has answers here:
'Return' keyword returns only one element from a loop?
(3 answers)
Closed 6 years ago.
I'm trying to create a function that takes mores code as an input in string format and returns the message decoded also as a string.
I've identified that i need to split the string where there is a space to ascertain each individual character in morse. and a loop to return a value if matched in dictionary key. I'm a beginner and going really wrong somewhere. Thanks in advance.
code_dict = {'.-...': '&', '--..--': ',', '....-': '4', '.....': '5',
'...---...': 'SOS', '-...': 'B', '-..-': 'X', '.-.': 'R',
'.--': 'W', '..---': '2', '.-': 'A', '..': 'I', '..-.': 'F',
'.': 'E', '.-..': 'L', '...': 'S', '..-': 'U', '..--..': '?',
'.----': '1', '-.-': 'K', '-..': 'D', '-....': '6', '-...-': '=',
'---': 'O', '.--.': 'P', '.-.-.-': '.', '--': 'M', '-.': 'N',
'....': 'H', '.----.': "'", '...-': 'V', '--...': '7', '-.-.-.': ';',
'-....-': '-', '..--.-': '_', '-.--.-': ')', '-.-.--': '!', '--.': 'G',
'--.-': 'Q', '--..': 'Z', '-..-.': '/', '.-.-.': '+', '-.-.': 'C', '---...': ':',
'-.--': 'Y', '-': 'T', '.--.-.': '#', '...-..-': '$', '.---': 'J', '-----': '0',
'----.': '9', '.-..-.': '"', '-.--.': '(', '---..': '8', '...--': '3'
}
def decodeMorse(morseCode):
for item in morseCode.split(' '):
return code_dict.get(item)
my problem is it only decodes the first character of the string entered in morse
return something instantly ends the function. You stop stop processing input after first character.
In other languages, you could instead create list (array) with results, and return that:
def decodeMorse(morseCode):
results = []
for item in morseCode.split(' '):
results.append(code_dict.get(item))
return results
Or, as #Bakuriu suggested:
def decodeMorse(morseCode):
for item in morseCode.split(' '):
return [code_dict.get(item) for item in morseCode.split(' ')]
There is however simple flaw with this approach -- it decodes whole string at once, even if you only need first few characters.
We can do better in Python.
Use yield instead of return:
def decodeMorse(morseCode):
for item in morseCode.split(' '):
yield code_dict.get(item)
Now, the function instead of returning whole list at once, returns generator which yields one character at once. If you don't need whole translation, it's likely to be faster. It'll also use less memory (you don't need to construct and keep in memory list of all the characters).
You can convert the generator into list (list(decodeMorse('... --- ...'))) or into string (''.join(decodeMorse('... --- ...'))) if you need to. You can also just iterate over it like over a sequence:
>>> decoded = decodeMorse('... --- ...')
>>> for char in decoded:
... print(char)
...
S
O
S
>>>
...except, you can only do it once:
>>> for char in decoded:
... print(char)
...
>>>
...because generators are disposable.
If you need to iterate over it another time, store it in list, or create another generator by calling decodeMorse again.

Categories

Resources