I'm new to Python, coming from Java and C. How can I increment a char? In Java or C, chars and ints are practically interchangeable, and in certain loops, it's very useful to me to be able to do increment chars, and index arrays by chars.
How can I do this in Python? It's bad enough not having a traditional for(;;) looper - is there any way I can achieve what I want to achieve without having to rethink my entire strategy?
In Python 2.x, just use the ord and chr functions:
>>> ord('c')
99
>>> ord('c') + 1
100
>>> chr(ord('c') + 1)
'd'
>>>
Python 3.x makes this more organized and interesting, due to its clear distinction between bytes and unicode. By default, a "string" is unicode, so the above works (ord receives Unicode chars and chr produces them).
But if you're interested in bytes (such as for processing some binary data stream), things are even simpler:
>>> bstr = bytes('abc', 'utf-8')
>>> bstr
b'abc'
>>> bstr[0]
97
>>> bytes([97, 98, 99])
b'abc'
>>> bytes([bstr[0] + 1, 98, 99])
b'bbc'
"bad enough not having a traditional for(;;) looper"?? What?
Are you trying to do
import string
for c in string.lowercase:
...do something with c...
Or perhaps you're using string.uppercase or string.letters?
Python doesn't have for(;;) because there are often better ways to do it. It also doesn't have character math because it's not necessary, either.
Check this: USING FOR LOOP
for a in range(5):
x='A'
val=chr(ord(x) + a)
print(val)
LOOP OUTPUT: A B C D E
I came from PHP, where you can increment char (A to B, Z to AA, AA to AB etc.) using ++ operator. I made a simple function which does the same in Python. You can also change list of chars to whatever (lowercase, uppercase, etc.) is your need.
# Increment char (a -> b, az -> ba)
def inc_char(text, chlist = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
# Unique and sort
chlist = ''.join(sorted(set(str(chlist))))
chlen = len(chlist)
if not chlen:
return ''
text = str(text)
# Replace all chars but chlist
text = re.sub('[^' + chlist + ']', '', text)
if not len(text):
return chlist[0]
# Increment
inc = ''
over = False
for i in range(1, len(text)+1):
lchar = text[-i]
pos = chlist.find(lchar) + 1
if pos < chlen:
inc = chlist[pos] + inc
over = False
break
else:
inc = chlist[0] + inc
over = True
if over:
inc += chlist[0]
result = text[0:-len(inc)] + inc
return result
There is a way to increase character using ascii_letters from string package which ascii_letters is a string that contains all English alphabet, uppercase and lowercase:
>>> from string import ascii_letters
>>> ascii_letters[ascii_letters.index('a') + 1]
'b'
>>> ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
Also it can be done manually;
>>> letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> letters[letters.index('c') + 1]
'd'
def doubleChar(str):
result = ''
for char in str:
result += char * 2
return result
print(doubleChar("amar"))
output:
aammaarr
For me i made the fallowing as a test.
string_1="abcd"
def test(string_1):
i = 0
p = ""
x = len(string_1)
while i < x:
y = (string_1)[i]
i=i+1
s = chr(ord(y) + 1)
p=p+s
print(p)
test(string_1)
Related
i am writing a script in python that replaces all the occurrences of an math functions such as log with there answers but soon after i came into this problem i am unable replace multiple occurrences of a function with its answer
text = "69+log(2)+log(3)-log(57)/420"
log_list = []
log_answer = []
z = ""
c = 0
hit_l = False
for r in text:
if hit_l:
c += 1
if c >= 4 and r != ")":
z += r
elif r == ")":
hit_l = False
if r == "l":
hit_l = True
log_list.append(z)
if z != '':
logs = log_list[-1]
logs = re.sub("og\\(", ";", logs)
log_list = logs.split(";")
for ans in log_list:
log_answer.append(math.log(int(ans)))
for a in log_answer:
text = re.sub(f"log\\({a}\\)", str(a), text)
i want to replace log(10) and log(2) with 1 and 0.301 respectively i tried using re.sub but it is not working i am not able to replace the respective functions with there answers any help will be appreciated thank you
Here is my take on this using eval along with re.sub with a callback function:
x = "log(10)+log(2)"
output = re.sub(r'log\((\d+(?:\.\d+)?)\)', lambda x: str(eval('math.log(' + x.group(1) + ', 10)')), x)
print(output) # 1.0+0.301029995664
As long as your string contains no spaces and there are + signs between different logarithmic functions, eval could be a way to do it.
>>> a = 'log(10)+log(2)'
>>> b = a.split('+')
>>> b
['log(10)', 'log(2)']
>>> from math import log10 as log
>>> [eval(i) for i in b]
[1.0, 0.3010299956639812]
EDIT:
You could repeatedly use str.replace method to replace all mathematical operators (if there are more than one) with whitespaces and eventually use str.split like:
>>> text.replace('+', ' ').replace('-', ' ').replace('*', ' ').replace('/', ' ').split()
['69', 'log(2)', 'log(3)', 'log(57)', '420']
def main():
cc = (input("Enter Message to Encrypt\n"))#user input
shift = int(2) #shift length
a=["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"] #reference list
newa={} #new shifted reference list
for i in range (0,len(a)):
newa [a[i]]=a[(i+shift)%len(a)]
#adds shifted 2 alaphabet into newalaphabet
#% moodulus used to wrap
for i in cc: #iterates through cc
if i in a:
a[i]=cc[i]
a[i]=newa[i]
main()
So I need input from the user #cc
the shift needs to be two
I used an alphabet list
then shift the alphabet by two to create newa
but I do not know how to apply the new alphabet to my user's input
Use a dictionary to map inputs to outputs
shifted_a = a[-shift:] + a[:-shift]
cipher = {a[i]: shifted_a[i] for i in range(len(a))}
output = ''.join(cipher[char] for char in cc)
Iterate through the string cc and replace all the alphabets using the get method of newa. Characters that are not in the dictionary are left as is, by passing them as the default to newa.get when the key is missing:
newa = {}
for i, x in enumerate(a):
newa[x] = a[(i+shift) % len(a)]
encrypted_text = ''.join(newa.get(i, i) for i in cc)
Python's builtin enumerate can be used in place of range(len(a)) in this case where you need the items in a and their respective indices.
Use mapping for every char, then join them back to create the encrypted message:
''.join(map(lambda x: chr((ord(x) - 97 + shift) % 26 + 97) if x in alphabet else x, cc.lower()))
Integrate it like that:
import string
alphabet = string.ascii_lowercase
cc = input('Enter string to encode: ')
shift = 2 # could be any number
encrypted = ''.join(map(lambda x: chr((ord(x) - 97 + shift) % 26 + 97) if x in alphabet else x, cc.lower()))
cc.lower() for the letters to be all same case (to map using constant ord)
chr((ord(x) - 97 + shift) % 26 + 97) :
get the value of the number minus 97 (0 for a, 1 for b, etc.).
apply the shift (a turns to c, etc.).
modulate by 26 to prevent letters like z from exceeding (25 + 2 = 27, 27 % 26 = 1 = b).
add 97 to bring the letter back to ascii standard (97 for a, 98 for b, etc.)
if x in alphabet else x cover for signs that are not letter (if you want to ignore spaces and punctuation use if x in alphabet else '' instead).
I would just build transition table and use it to decode string.
import string
shift = 2
letters = string.ascii_lowercase + string.ascii_uppercase
transtable = str.maketrans({letters[i]: letters[(i + shift) % len(letters)]
for i in range(len(letters))})
cc = input('Enter string to encode: ')
print(cc.translate(transtable))
I'll throw my solution in there. It should be pretty clear how it works...
import string
index_lookup = {letter: index for index, letter in enumerate(string.ascii_lowercase)}
def caesar_letter(l, shift=2):
new_index = index_lookup[l] + shift
return string.ascii_lowercase[new_index % len(index_lookup)]
def caesar_word(s):
return ''.join([caesar_letter(letter) for letter in s])
I think the above is better for readability but if you're opposed to imports...
index_lookup = {chr(idx): idx - ord('a') for idx in range(ord('a'), ord('z')+1)}
...
In [5]: caesar_word('abcdefghijklmnopqrstuvwxyz')
Out[5]: 'cdefghijklmnopqrstuvwxyzab'
I am trying to convert alphanumeric string with maximum length of 40 characters to an integer as small as possible so that we can easily save and retrieve from database. I am not aware if there is any python method existing for it or any simple algorithms we can use. To be specific my string will have only characters 0-9 and a-g. So kindly help with any suggestions on how we can uniquely convert from string to int and vice versa. I am using Python 2.7 on Cent os 6.5
This is not that difficult:
def str2int(s, chars):
i = 0
for c in reversed(s):
i *= len(chars)
i += chars.index(c)
return i
def int2str(i, chars):
s = ""
while i:
s += chars[i % len(chars)]
i //= len(chars)
return s
Example:
>>> chars = "".join(str(n) for n in range(10)) + "abcdefg"
>>> str2int("0235abg02", chars)
14354195089
>>> int2str(_, chars)
'0235abg02'
Basically if you want to encode n characters into an integer you interpret it as base-n.
There are 17 symbols in your input, so you can treat is as a base-17 number:
>>> int('aga0',17)
53924
For the reverse conversion, there are lots of solutions over here.
Improving on the above answers:
# The location of a character in the string matters.
chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
charsLen = len(chars)
def numberToStr(num):
s = ""
while num:
s = self.chars[num % charsLen] + s
num //= charsLen
return s # Or e.g. "s.zfill(10)"
Can handle strings with leading 0s:
def strToNumber(numStr):
num = 0
for i, c in enumerate(reversed(numStr)):
num += chars.index(c) * (charsLen ** i)
return num
I want to replace each character of a string by a different one, shifted over in the alphabet. I'm shifting by 2 in the example below, so a -> c, b -> d, etc.
I'm trying to use a regular expression and the sub function to accomplish this, but I'm getting an error.
This is the code that I have:
p = re.compile(r'(\w)')
test = p.sub(chr(ord('\\1') + 2), text)
print test
where the variable text is an input string.
And I'm getting this error:
TypeError: ord() expected a character, but string of length 2 found
I think the problem is that I the ord function is being called on the literal string "\1" and not on the \w character matched by the regular expression. What is the right way to do this?
It won't work like this. Python first runs chr(ord('\\') + 2 and then passes that result to p.sub.
You need to put it in a separate function or use an anonymous function (lambda):
p = re.compile(r'(\w)')
test = p.sub(lambda m: chr(ord(m.group(1)) + 2), text)
print test
Or better yet use maketrans instead of regular expressions:
import string
shift = 2
t = string.maketrans(string.ascii_lowercase, string.ascii_lowercase[shift:] +
string.ascii_lowercase[:shift])
string.translate(text, t)
Full version
def shouldShift(char):
return char in string.lowercase
def caesarShift(string, n):
def letterToNum(char):
return ord(char)-ord('a')
def numToLetter(num):
return chr(num+ord('a'))
def shiftByN(char):
return numToLetter((letterToNum(char)+n) % 26)
return ''.join((shiftByN(c) if shouldShift(c) else c) for c in string.lower())
One-liner
If you really want a one-liner, it would be this, but I felt it was uglier:
''.join(chr((ord(c)-ord('a')+n)%26 + ord('a')) for c in string)
Demo
>>> caesarShift(string.lowercase, 3)
'defghijklmnopqrstuvwxyzabc'
Try this, using list comprehensions:
input = 'ABC'
''.join(chr(ord(c)+2) for c in input)
> 'CDE'
It's simpler than using regular expressions.
def CaesarCipher(s1,num):
new_str = ''
for i in s1:
asc_V = ord(i)
if asc_V in range(65, 91):
if asc_V + num > 90:
asc_val = 65 + (num - 1 - (90 - asc_V))
else:
asc_val = asc_V + num
new_str = new_str + chr(asc_val)
elif (asc_V in range(97, 123)):
if asc_V + num > 122:
asc_val = 97 + (num - 1 - (122 - asc_V))
else:
asc_val = asc_V + num
new_str = new_str + chr(asc_val)
else:
new_str = new_str + i
return new_str
print (CaesarCipher("HEllo", 4))
print (CaesarCipher("xyzderBYTE", 2))
strings = ["1 asdf 2", "25etrth", "2234342 awefiasd"] #and so on
Which is the easiest way to get [1, 25, 2234342]?
How can this be done without a regex module or expression like (^[0-9]+)?
One could write a helper function to extract the prefix:
def numeric_prefix(s):
n = 0
for c in s:
if not c.isdigit():
return n
else:
n = n * 10 + int(c)
return n
Example usage:
>>> strings = ["1asdf", "25etrth", "2234342 awefiasd"]
>>> [numeric_prefix(s) for s in strings]
[1, 25, 2234342]
Note that this will produce correct output (zero) when the input string does not have a numeric prefix (as in the case of empty string).
Working from Mikel's solution, one could write a more concise definition of numeric_prefix:
import itertools
def numeric_prefix(s):
n = ''.join(itertools.takewhile(lambda c: c.isdigit(), s))
return int(n) if n else 0
new = []
for item in strings:
new.append(int(''.join(i for i in item if i.isdigit())))
print new
[1, 25, 2234342]
Basic usage of regular expressions:
import re
strings = ["1asdf", "25etrth", "2234342 awefiasd"]
regex = re.compile('^(\d*)')
for s in strings:
mo = regex.match(s)
print s, '->', mo.group(0)
1asdf -> 1
25etrth -> 25
2234342 awefiasd -> 2234342
Building on sahhhm's answer, you can fix the "1 asdf 1" problem by using takewhile.
from itertools import takewhile
def isdigit(char):
return char.isdigit()
numbers = []
for string in strings:
result = takewhile(isdigit, string)
resultstr = ''.join(result)
if resultstr:
number = int(resultstr)
if number:
numbers.append(number)
So you only want the leading digits? And you want to avoid regexes? Probably there's something shorter but this is the obvious solution.
nlist = []
for s in strings:
if not s or s[0].isalpha(): continue
for i, c in enumerate(s):
if not c.isdigit():
nlist.append(int(s[:i]))
break
else:
nlist.append(int(s))