I need to be able to cycle through a string of characters using the modulo operator so that each character can be passed to a function. This is a simple question, I know, but I am seriously confused as to how to do it. Here is what I have but it gives me the error "TypeError: not all arguments converted during string formatting". Any suggestions would be appreciated.
key = 'abc'
def encrypt(key,string):
c = ''
for i in range(0,len(string)):
t = (key)%3
a = XOR(ord(string[i]),ord(t))
b = chr(a)
c = c + b
return(c)
Ingredients
Here are some ingredients which help you write your encrypt function in a concise way:
You can directly iterate over the characters of a string:
>>> my_string = 'hello'
>>> for c in my_string:
... print(c)
...
h
e
l
l
o
You can cycle through any iterable (like, for example, a string) using the cycle function from the itertools module of the standard library:
>>> from itertools import cycle
>>> for x in cycle('abc'):
... print(x)
...
a
b
c
a
b
c
a
# goes on infinitely, abort with Ctrl-C
You can use the zip function to iterate over two sequences at the same time:
>>> for a, b in zip('hello', 'world'):
... print(a, b)
...
h w
e o
l r
l l
o d
Edit: as kichik suggests, you can also use itertools.izip which is beneficial if you deal with very large input strings.
You calculate the xor of two numbers by using the ^ operator:
>>> 5 ^ 3
6
You can concatenate a sequence of individual strings to a single string using the join function:
>>> ''.join(['hello', 'how', 'are', 'you'])
'hellohowareyou'
You can feed join with a so-called generator expression, which is similar to a for loop, but as a single expression:
>>> ''.join(str(x+5) for x in range(3))
'567'
Putting it all together
from itertools import cycle, izip
def encrypt(key, string):
return ''.join(chr(ord(k) ^ ord(c))
for k, c in izip(cycle(key), string))
You can (probably should) iterate over the characters without using range() and you'll want to run ord() on each character before you run mod on it, as the % operator means something else for a string. This should work:
key = 'abc'
for c in key:
print XOR(ord(c), ord(c) % 3)
You can use itertools.cycle() to cycle through the key and itertools.izip() for an easy combination of the two.
import itertools
def encrypt(key, string):
keyi = itertools.cycle(key)
result = ''
for k, v in itertools.izip(keyi, string):
a = ord(v) ^ ord(k)
result += chr(a)
return result
And then use it like this:
>>> encrypt('\x00', 'abc')
'abc'
>>> encrypt('\x01', 'abc')
'`cb'
You got an error about formatting because % is not a modulo operator for strings. It's used for formatting strings. You probably meant to use something like this:
key[i%3]
Related
Question has been asked that is similar but all post on here refer to replacing single characters. I'm trying to replace a whole word in a string. I've replaced it but I cant print it with spaces in between.
Here is the function replace that replaces it:
def replace(a, b, c):
new = b.split()
result = ''
for x in new:
if x == a:
x = c
result +=x
print(' '.join(result))
Calling it with:
replace('dogs', 'I like dogs', 'kelvin')
My result is this:
i l i k e k e l v i n
What I'm looking for is:
I like kelvin
The issue here is that result is a string and when join is called it will take each character in result and join it on a space.
Instead, use a list , append to it (it's also faster than using += on strings) and print it out by unpacking it.
That is:
def replace(a, b, c):
new = b.split(' ')
result = []
for x in new:
if x == a:
x = c
result.append(x)
print(*result)
print(*result) will supply the elements of the result list as positional arguments to print which prints them out with a default white space separation.
"I like dogs".replace("dogs", "kelvin") can of course be used here but I'm pretty sure that defeats the point.
Substrings and space preserving method:
def replace(a, b, c):
# Find all indices where 'a' exists
xs = []
x = b.find(a)
while x != -1:
xs.append(x)
x = b.find(a, x+len(a))
# Use slice assignment (starting from the last index)
result = list(b)
for i in reversed(xs):
result[i:i+len(a)] = c
return ''.join(result)
>>> replace('dogs', 'I like dogs dogsdogs and hotdogs', 'kelvin')
'I like kelvin kelvinkelvin and hotkelvin'
Just make result a list, and the joining will work:
result = []
You are just generating one long string and join its chars.
I'm trying to do the following:
>>>func = lambda string,i=0: string[index]
>>> func('HEY')
H
>>> func('HEY')
E
>>> func('HEY')
Y
How can i save and increment index each time(without creating index as global)
thanks
Solution 1
You can create a generator function, like this
def get_next_char(actual_string):
for char in actual_string:
yield char
Then, you need to create a generator object, like this
next_char = get_next_char("HEY")
That's it. You can now get the next character with next function, like this
>>> next(next_char)
H
>>> next(next_char)
E
>>> next(next_char)
Y
Solution 2
You can simply use the String's iterator, like this
get_char = iter("HEY")
>>> next(get_char)
H
>>> next(get_char)
E
>>> next(get_char)
Y
Is it possible without regex in python to print the first n integers from a string containing both integers and characters?
For instance:
string1 = 'test120202test34234e23424'
string2 = 'ex120202test34234e23424'
foo(string1,6) => 120202
foo(string2,6) => 120202
Anything's possible without a regex. Most things are preferable without a regex.
On easy way is.
>>> str = 'test120202test34234e23424'
>>> str2 = 'ex120202test34234e23424'
>>> ''.join(c for c in str if c.isdigit())[:6]
'120202'
>>> ''.join(c for c in str2 if c.isdigit())[:6]
'120202'
You might want to handle your corner cases some specific way -- it all depends on what you know your code should do.
>>> str3 = "hello 4 world"
>>> ''.join(c for c in str3 if c.isdigit())[:6]
'4'
And don't name your strings str!
You can remove all the alphabets from you string with str.translate and the slice till the number of digits you want, like this
import string
def foo(input_string, num):
return input_string.translate(None, string.letters)[:num]
print foo('test120202test34234e23424', 6) # 120202
print foo('ex120202test34234e23424', 6) # 120202
Note: This simple technique works only in Python 2.x
But the most efficient way is to go with the itertools.islice
from itertools import islice
def foo(input_string, num):
return "".join(islice((char for char in input_string if char.isdigit()),num))
This is is the most efficient way because, it doesn't have to process the entire string before returning the result.
If you didn't want to process the whole string - not a problem with the length of strings you give as an example - you could try:
import itertools
"".join(itertools.islice((c for c in str2 if c.isdigit()),0,5))
Assume I have a string as follows: expression = '123 + 321'.
I am walking over the string character-by-character as follows: for p in expression. I am I am checking if p is a digit using p.isdigit(). If p is a digit, I'd like to grab the whole number (so grab 123 and 321, not just p which initially would be 1).
How can I do that in Python?
In C (coming from a C background), the equivalent would be:
int x = 0;
sscanf(p, "%d", &x);
// the full number is now in x
EDIT:
Basically, I am accepting a mathematical expression from a user that accepts positive integers, +,-,*,/ as well as brackets: '(' and ')'. I am walking the string character by character and I need to be able to determine whether the character is a digit or not. Using isdigit(), I can that. If it is a digit however, I need to grab the whole number. How can that be done?
>>> from itertools import groupby
>>> expression = '123 + 321'
>>> expression = ''.join(expression.split()) # strip whitespace
>>> for k, g in groupby(expression, str.isdigit):
if k: # it's a digit
print 'digit'
print list(g)
else:
print 'non-digit'
print list(g)
digit
['1', '2', '3']
non-digit
['+']
digit
['3', '2', '1']
This is one of those problems that can be approached from many different directions. Here's what I think is an elegant solution based on itertools.takewhile:
>>> from itertools import chain, takewhile
>>> def get_numbers(s):
... s = iter(s)
... for c in s:
... if c.isdigit():
... yield ''.join(chain(c, takewhile(str.isdigit, s)))
...
>>> list(get_numbers('123 + 456'))
['123', '456']
This even works inside a list comprehension:
>>> def get_numbers(s):
... s = iter(s)
... return [''.join(chain(c, takewhile(str.isdigit, s)))
... for c in s if c.isdigit()]
...
>>> get_numbers('123 + 456')
['123', '456']
Looking over other answers, I see that this is not dissimilar to jamylak's groupby solution. I would recommend that if you don't want to discard the extra symbols. But if you do want to discard them, I think this is a bit simpler.
The Python documentation includes a section on simulating scanf, which gives you some idea of how you can use regular expressions to simulate the behavior of scanf (or sscanf, it's all the same in Python). In particular, r'\-?\d+' is the Python string that corresponds to the regular expression for an integer. (r'\d+' for a nonnegative integer.) So you could embed this in your loop as
integer = re.compile(r'\-?\d+')
for p in expression:
if p.isdigit():
# somehow find the current position in the string
integer.match(expression, curpos)
But that still reflects a very C-like way of thinking. In Python, your iterator variable p is really just an individual character that has actually been pulled out of the original string and is standing on its own. So in the loop, you don't naturally have access to the current position within the string, and trying to calculate it is going to be less than optimal.
What I'd suggest instead is using Python's built in regexp matching iteration method:
integer = re.compile(r'\-?\d+') # only do this once in your program
all_the_numbers = integer.findall(expression)
and now all_the_numbers is a list of string representations of all the integers in the expression. If you wanted to actually convert them to integers, then you could do this instead of the last line:
all_the_numbers = [int(s) for s in integer.finditer(expression)]
Here I've used finditer instead of findall because you don't have to make a list of all the strings before iterating over them again to convert them to integers.
Though I'm not familiar with sscanf, I'm no C developer, it looks like it's using format strings in a way not dissimilar to what I'd use python's re module for. Something like this:
import re
nums = re.compile('\d+')
found = nums.findall('123 + 321')
# if you know you're only looking for two values.
left, right = found
You can use shlex http://docs.python.org/library/shlex.html
>>> from shlex import shlex
>>> expression = '123 + 321'
>>> for e in shlex(expression):
... print e
...
123
+
321
>>> expression = '(92831 * 948) / 32'
>>> for e in shlex(expression):
... print e
...
(
92831
*
948
)
/
32
I'd split the string up on the ' + ' string, giving you what's outside of them:
>>> expression = '123 + 321'
>>> ex = expression.split(' + ')
>>> ex
['123', '321']
>>> int_ex = map(int, ex)
>>> int_ex
[123, 321]
>>> sum(int_ex)
444
It's dangerous, but you could use eval:
>>> eval('123 + 321')
444
I'm just taking a stab at you parsing the string, and doing raw calculations on it.
e_array = expression.split('+')
i_array = map(int, e_array)
And i_array holds all integers in the expression.
UPDATE
If you already know all the special characters in your expression and you want to eliminate them all
import re
e_array = re.split('[*/+\-() ]', expression) # all characters here is mult, div, plus, minus, left- right- parathesis and space
i_array = map(int, filter(lambda x: len(x), e_array))
How can I remove duplicate characters from a string using Python? For example, let's say I have a string:
foo = 'mppmt'
How can I make the string:
foo = 'mpt'
NOTE: Order is not important
If order does not matter, you can use
"".join(set(foo))
set() will create a set of unique letters in the string, and "".join() will join the letters back to a string in arbitrary order.
If order does matter, you can use a dict instead of a set, which since Python 3.7 preserves the insertion order of the keys. (In the CPython implementation, this is already supported in Python 3.6 as an implementation detail.)
foo = "mppmt"
result = "".join(dict.fromkeys(foo))
resulting in the string "mpt". In earlier versions of Python, you can use collections.OrderedDict, which has been available starting from Python 2.7.
If order does matter, how about:
>>> foo = 'mppmt'
>>> ''.join(sorted(set(foo), key=foo.index))
'mpt'
If order is not the matter:
>>> foo='mppmt'
>>> ''.join(set(foo))
'pmt'
To keep the order:
>>> foo='mppmt'
>>> ''.join([j for i,j in enumerate(foo) if j not in foo[:i]])
'mpt'
Create a list in Python and also a set which doesn't allow any duplicates.
Solution1 :
def fix(string):
s = set()
list = []
for ch in string:
if ch not in s:
s.add(ch)
list.append(ch)
return ''.join(list)
string = "Protiijaayiiii"
print(fix(string))
Method 2 :
s = "Protijayi"
aa = [ ch for i, ch in enumerate(s) if ch not in s[:i]]
print(''.join(aa))
Method 3 :
dd = ''.join(dict.fromkeys(a))
print(dd)
As was mentioned "".join(set(foo)) and collections.OrderedDict will do.
A added foo = foo.lower() in case the string has upper and lower case characters and you need to remove ALL duplicates no matter if they're upper or lower characters.
from collections import OrderedDict
foo = "EugeneEhGhsnaWW"
foo = foo.lower()
print "".join(OrderedDict.fromkeys(foo))
prints eugnhsaw
#Check code and apply in your Program:
#Input= 'pppmm'
s = 'ppppmm'
s = ''.join(set(s))
print(s)
#Output: pm
If order is important,
seen = set()
result = []
for c in foo:
if c not in seen:
result.append(c)
seen.add(c)
result = ''.join(result)
Or to do it without sets:
result = []
for c in foo:
if c not in result:
result.append(c)
result = ''.join(result)
def dupe(str1):
s=set(str1)
return "".join(s)
str1='geeksforgeeks'
a=dupe(str1)
print(a)
works well if order is not important.
d = {}
s="YOUR_DESIRED_STRING"
res=[]
for c in s:
if c not in d:
res.append(c)
d[c]=1
print ("".join(res))
variable 'c' traverses through String 's' in the for loop and is checked if c is in a set d (which initially has no element) and if c is not in d, c is appended to the character array 'res' then the index c of set d is changed to 1. after the loop is exited i.e c finishes traversing through the string to store unique elements in set d, the resultant res which has all unique characters is printed.
Using regular expressions:
import re
pattern = r'(.)\1+' # (.) any character repeated (\+) more than
repl = r'\1' # replace it once
text = 'shhhhh!!!
re.sub(pattern,repl,text)
output:
sh!
As string is a list of characters, converting it to dictionary will remove all duplicates and will retain the order.
"".join(list(dict.fromkeys(foo)))
Functional programming style while keeping order:
import functools
def get_unique_char(a, b):
if b not in a:
return a + b
else:
return a
if __name__ == '__main__':
foo = 'mppmt'
gen = functools.reduce(get_unique_char, foo)
print(''.join(list(gen)))
def remove_duplicates(value):
var=""
for i in value:
if i in value:
if i in var:
pass
else:
var=var+i
return var
print(remove_duplicates("11223445566666ababzzz###123#*#*"))
from collections import OrderedDict
def remove_duplicates(value):
m=list(OrderedDict.fromkeys(value))
s=''
for i in m:
s+=i
return s
print(remove_duplicates("11223445566666ababzzz###123#*#*"))
mylist=["ABA", "CAA", "ADA"]
results=[]
for item in mylist:
buffer=[]
for char in item:
if char not in buffer:
buffer.append(char)
results.append("".join(buffer))
print(results)
output
ABA
CAA
ADA
['AB', 'CA', 'AD']