def string_transf():
input('Enter a word or string')
#letters = 'abcdefghijklmnopqrstvwxyz'
#for i in letters:
#i+=
if c >= 'a' and c <='z':
i = 'z' - c + 'a'
print(i)
I tried to come up with an algorithm, but I'm lost.
Since you didn't say you want to handle uppercase letters, here is a single line answer:
>>> ''.join(chr(122 - ord(c) + 97) for c in 'abcd')
'zyxw'
Where 122 is ord('z') and 97 is ord('a'). ord function converts the character to its Unicode code point and chr function does the opposite.
You can skip non lowercase characters if you will:
>>> ''.join(chr(122 - ord(c) + 97) for c in 'abcdEFG' if 'a' <= c <= 'z')
'zyxw'
If you want to handle uppercase following the same model:
>>> def inv(c):
... if 'a' <= c <= 'z':
... return chr(122 - ord(c) + 97)
... if 'A' <= c <= 'Z':
... return chr(90 - ord(c) + 65)
... return c
...
>>> ''.join(inv(c) for c in 'Hello world!')
'Svool dliow!'
You can use the following approach.
Create a dictionary my_map, which describes the character's translation:
import string
ascii_alph = string.ascii_lowercase
my_map = dict(zip(ascii_alph, ascii_alph[::-1]))
str_input = 'abcd'
str_output = ''.join(my_map[c] for c in str_input) # assume every c in my_map
print(str_output) # zyxw
Also you can implement that with the translate method:
# my_map = string.maketrans(ascii_alph, ascii_alph[::-1]) # Python 2
my_map = str.maketrans(ascii_alph, ascii_alph[::-1]) # Python 3
str_input = 'abcd'
str_output = str_input.translate(my_map)
print(str_output) # zyxw
For the general case (ASCII uppercase and other chars) you can always expand 'my_map' dictionary.
Note that the described approach is quite flexible since it allows you to make translation not only for the case of inversion of the alphabet.
Related
This question already has answers here:
How to count sequentially using letters instead of numbers?
(3 answers)
Closed 2 months ago.
I need a method that 'increments' the string a to z and than aa to az and then ba to bz and so on, like the columns in an excel sheet. I will feed the method the previous string and it should increment to the next letter.
PSEUDO CODE
def get_next_letter(last_letter):
return last_letter += 1
So I could use it like so:
>>> get_next_letter('a')
'b'
>>> get_next_letter('b')
'c'
>>> get_next_letter('c')
'd'
...
>>> get_next_letter('z')
'aa'
>>> get_next_letter('aa')
'ab'
>>> get_next_letter('ab')
'ac'
...
>>> get_next_letter('az')
'ba'
>>> get_next_letter('ba')
'bb'
...
>>> get_next_letter('zz')
'aaa'
I believe there are better ways to handle this, but you can implement the algorithm for adding two numbers on paper...
def get_next_letter(string):
x = list(map(ord, string)) # convert to list of numbers
x[-1] += 1 # increment last element
result = ''
carry = 0;
for c in reversed(x):
result = chr((c + carry )) + result # i'm not accounting for when 'z' overflows here
carry = c > ord('z')
if carry: # add the new letter at the beggining in case there is still carry
result = 'a' + result
return result.replace('{', 'a') # replace overflowed 'z' with 'a'
all proposed are just way too complicated
I came up with below, using a recursive call,
this is it!
def getNextLetter(previous_letter):
"""
'increments' the provide string to the next letter recursively
raises TypeError if previous_letter is not a string
returns "a" if provided previous_letter was emtpy string
"""
if not isinstance(previous_letter, str):
raise TypeError("the previous letter should be a letter, doh")
if previous_letter == '':
return "a"
for letter_location in range(len(previous_letter) - 1, -1, -1):
if previous_letter[letter_location] == "z":
return getNextLetter(previous_letter[:-1])+"a"
else:
characters = "abcdefghijklmnopqrstuvwxyz"
return (previous_letter[:-1])\
+characters[characters.find(previous_letter[letter_location])+1]
# EOF
Why not use openpyxl's get_column_letter and column_index_from_string
from openpyxl.utils import get_column_letter, column_index_from_string
# or `from openpyxl.utils.cell import get_column_letter, column_index_from_string`
def get_next_letter(s: str) -> str:
return get_column_letter(
column_index_from_string(s) + 1
).lower()
and then
>>> get_next_letter('aab')
'aac'
>>> get_next_letter('zz')
'aaa'
?
Keeping in mind that this solution only works in [A, ZZZ[.
I fact what you want to achieve is increment a number expressed in base26 (using the 26 alphabet letters as symbols).
We all know decimal base that we use daily.
We know hexadecimal that is in fact base16 with symbols including digits and a, b, c, d, e, f.
Example : 0xff equals 15.
An approach is to convert into base10, increment the result decimal number, then convert it back to base26.
Let me explain.
I define 2 functions.
A first function to convert a string (base26) into a base10 (decimal) number.
str_tobase10("abcd") # 19010
The inverse function to convert a base10 number (decimal) to a string (base26).
base10_tostr(19010) # abcd
get_next_letter() just has to convert the string to a number, increment by one and converts back to a string.
Advantages :
pure Python, no extra lib/dependency required.
works with very long strings
Example :
get_next_letter("abcdefghijz") # abcdefghika
def str_tobase10(value: str) -> int:
n = 0
for letter in value:
n *= 26
n += ord(letter)-ord("a")+1
return n
def base10_tostr(value: int) -> str:
s = ""
n = value
while n > 26:
r = n % 26
s = chr(ord("a")-1+r) + s
n = n // 26
return chr(ord("a")-1+n) + s
def get_next_letter(value: str):
n = str_tobase10(value)
return base10_tostr(n+1)
What I mean by the question is if I had:
alphabet:["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"]
and received an input of "a" I would get back an index of 1, or z to get back an index of 26, from the tuple's index. I'm wondering if there is an easier way instead of using a dictionary.
So like if I receive an input of an item from the alphabet tuple, it will return the index.
I am asking this because I am creating a simple caesar cipher encode/decoder and I just want to add 3 to the index which will then be used to create another variable that has the whole alphabet shifted by an index of 3 so "a" becomes "d" and "z" becomes "c".
same trick as with C, assuming english alphabet:
idx = ord(x) - ord('a') + 1
(The plus one because you requested '1' for the value 'a')
string.ascii_lowercase already has all letters in order (as a string), so you could define a function like:
from string import ascii_lowercase
def letter_position(letter: str) -> int:
if len(letter) > 1:
return 0
return ascii_lowercase.find(letter.lower()) + 1
This function works both with uppercase and lowercase letters, and returns 0 if something other than a single alphabet letter is passed onto it (so 'a' returns 1, 'B' returns 2, but 'ab' and '!' both return 0):
>>> letter_position('a')
1
>>> letter_position('B')
2
>>> letter_position('ab')
0
>>> letter_position('!')
0
Dictionary is the right way to go here. You should handle any "offsets" with a function outside of the dictionary.
# secret coder
alphabet = list('abcdefghijklmnopqrstuvwxyz ')
# make dictionaries for encode / decode
key = {ltr:idx for idx, ltr in enumerate(alphabet)}
reverse_key = {idx:ltr for idx, ltr in enumerate(alphabet)}
# do the "tricky stuff" with a function
def encode(word, offset):
result = []
for letter in word:
result.append(key[letter] + offset)
return result
def decode(code, offset):
result = []
for num in code:
result.append(reverse_key[num - offset])
return ''.join(result)
# take it for a test drive...
secret_key = 5 # select anything you want, just use same for encode/decode
secret = encode('dog food', secret_key)
print(secret)
# get back the original w/ the secret key
retrieved = decode(secret, secret_key)
print(retrieved)
Output:
[8, 19, 11, 31, 10, 19, 19, 8]
dog food
Here's your caeser cipher:
from string import ascii_lowercase
def encode(s, offset):
offset %= 26
result = []
for ch in s:
substitute = ascii_lowercase.index(ch) + offset
result.append(ascii_lowercase[substitute % 26])
return ''.join(result)
def decode(s, offset):
offset %= 26
result = []
for ch in s:
original = ascii_lowercase.index(ch) - offset
result.append(ascii_lowercase[original])
return ''.join(result)
if __name__ == '__main__':
s = 'abcdefwxyza'
for i in range(-100, 100):
assert(decode(encode(s, i), i) == s)
To encode/decode a string, translate / make_trans could be used to create a cipher.
from string import ascii_lowercase as lc, ascii_uppercase as uc
def encode(s, offset):
return s.translate(
str.maketrans(lc+uc,
lc[offset:]+lc[:offset]+uc[offset:]+uc[:offset]))
def decode(s, offset):
return s.translate(
str.maketrans(lc+uc,
lc[26-offset:]+lc[:26-offset]+uc[26-offset:]+uc[:26-offset]))
s = 'Hello World!'
encoded = encode(s, 3)
print(encoded)
decoded = decode(encoded, 3)
print(decoded)
Prints
Khoor Zruog!
Hello World!
I was wondering if it is possible to convert numbers into their corresponding alphabetical value. So
1 -> a
2 -> b
I was planning to make a program which lists all the alphabetical combinations possible for a length specified by a user.
See I know how to build the rest of the program except this!
Any help would be wonderful.
Big Letter:
chr(ord('#')+number)
1 -> A
2 -> B
...
Small Letter:
chr(ord('`')+number)
1 -> a
2 -> b
...
import string
for x, y in zip(range(1, 27), string.ascii_lowercase):
print(x, y)
or
import string
for x, y in enumerate(string.ascii_lowercase, 1):
print(x, y)
or
for x, y in ((x + 1, chr(ord('a') + x)) for x in range(26)):
print(x, y)
All of the solutions above output lowercase letters from English alphabet along with their position:
1 a
...
26 z
You'd create a dictionary to access letters (values) by their position (keys) easily. For example:
import string
d = dict(enumerate(string.ascii_lowercase, 1))
print(d[3]) # c
You can use chr() to turn numbers into characters, but you need to use a higher starting point as there are several other characters in the ASCII table first.
Use ord('a') - 1 as a starting point:
start = ord('a') - 1
a = chr(start + 1)
Demo:
>>> start = ord('a') - 1
>>> a = chr(start + 1)
>>> a
'a'
Another alternative is to use the string.ascii_lowercase constant as a sequence, but you need to start indexing from zero:
import string
a = string.ascii_lowercase[0]
What about a dictionary?
>>> import string
>>> num2alpha = dict(zip(range(1, 27), string.ascii_lowercase))
>>> num2alpha[2]
b
>>> num2alpha[25]
y
But don't go over 26:
>>> num2alpha[27]
KeyError: 27
But if you are looking for all alphabetical combinations of a given length:
>>> import string
>>> from itertools import combinations_with_replacement as cwr
>>> alphabet = string.ascii_lowercase
>>> length = 2
>>> ["".join(comb) for comb in cwr(alphabet, length)]
['aa', 'ab', ..., 'zz']
Try a dict and some recursion:
def Getletterfromindex(self, num):
#produces a string from numbers so
#1->a
#2->b
#26->z
#27->aa
#28->ab
#52->az
#53->ba
#54->bb
num2alphadict = dict(zip(range(1, 27), string.ascii_lowercase))
outval = ""
numloops = (num-1) //26
if numloops > 0:
outval = outval + self.Getletterfromindex(numloops)
remainder = num % 26
if remainder > 0:
outval = outval + num2alphadict[remainder]
else:
outval = outval + "z"
return outval
Here is a quick solution:
# assumes Python 2.7
OFFSET = ord("a") - 1
def letter(num):
return chr(num + OFFSET)
def letters_sum_to(total):
for i in xrange(1, min(total, 27)):
for rem in letters_sum_to(total - i):
yield [letter(i)] + rem
if total <= 26:
yield [letter(total)]
def main():
for letters in letters_sum_to(8):
print("".join(letters))
if __name__=="__main__":
main()
which produces
aaaaaaaa
aaaaaab
aaaaaba
aaaaac
aaaabaa
aaaabb
aaaaca
aaaad
aaabaaa
# etc
Note that the number of solutions totalling to N is 2**(N-1).
for i in range(0, 100):
mul = 1
n = i
if n >= 26:
n = n-26
mul = 2
print chr(65+n)*mul
this code should take a char as an argument and print out that char in alphabetically order to 'a' and reverse to char.
>>> characters('d')
d c b a b c d
this is what Ii wrote so far but it is not the correct output
def characters(char):
numb=ord(char)
while numb>ord('a'):
>> print chr(numb),
numb=numb-1
return
>>> characters('h')
g f e d c b a
def characters(c):
print ' '.join(map(chr, range(ord(c), ord('a'), -1) + range(ord('a'), ord(c)+1)))
>>> characters('d')
d c b a b c d
or
def characters(c):
for n in xrange(ord(c), ord('a'), -1):
print chr(n),
for n in xrange(ord('a'), ord(c)+1):
print chr(n),
print
Well, you're halfway there as it stands. Now you just have to figure out how to take numb back to your letter.
In order to make it go backwards in the alphabet, you're using numb=numb-1. So in order to make it go forward in the alphabet, what would be the opposite of that? Then you could put that in another loop afterwards.
I need a simple program that given a string, returns to me the next one in the alphanumeric ordering (or just the alphabetic ordering).
f("aaa")="aab"
f("aaZ")="aba"
And so on.
Is there a function for this in one of the modules already?
I don't think there's a built-in function to do this. The following should work:
def next_string(s):
strip_zs = s.rstrip('z')
if strip_zs:
return strip_zs[:-1] + chr(ord(strip_zs[-1]) + 1) + 'a' * (len(s) - len(strip_zs))
else:
return 'a' * (len(s) + 1)
Explanation: you find the last character which is not a z, increment it, and replace all of the characters after it with a's. If the entire string is z's, then return a string of all a's that is one longer.
Are the answers at How would you translate this from Perl to Python? sufficient? Not 100% what you're asking, but close...
A different, longer, but perhaps more readable and flexible solution:
def toval(s):
"""Converts an 'azz' string into a number"""
v = 0
for c in s.lower():
v = v * 26 + ord(c) - ord('a')
return v
def tostr(v, minlen=0):
"""Converts a number into 'azz' string"""
s = ''
while v or len(s) < minlen:
s = chr(ord('a') + v % 26) + s
v /= 26
return s
def next(s, minlen=0):
return tostr(toval(s) + 1, minlen)
s = ""
for i in range(100):
s = next(s, 5)
print s
You convert the string into a number where each letter represents a digit in base 26, increase the number by one and convert the number back into the string. This way you can do arbitrary math on values represented as strings of letters.
The ''minlen'' parameter controls how many digits the result will have (since 0 == a == aaaaa).
Sucks that python doesn't have what ruby has: String#next So here's a shitty solution to deal with alpha-numerical strings:
def next_string(s):
a1 = range(65, 91) # capital letters
a2 = range(97, 123) # letters
a3 = range(48, 58) # numbers
char = ord(s[-1])
for a in [a1, a2, a3]:
if char in a:
if char + 1 in a:
return s[:-1] + chr(char + 1)
else:
ns = next_string(s[:-1]) if s[:-1] else chr(a[0])
return ns + chr(a[0])
print next_string('abc') # abd
print next_string('123') # 124
print next_string('ABC') # ABD
# all together now
print next_string('a0') # a1
print next_string('1a') # 1b
print next_string('9A') # 9B
# with carry-over
print next_string('9') # 00
print next_string('z') # aa
print next_string('Z') # AA
# cascading carry-over
print next_string('a9') # b0
print next_string('0z') # 1a
print next_string('Z9') # AA0
print next_string('199') # 200
print next_string('azz') # baa
print next_string('Zz9') # AAa0
print next_string('$a') # $b
print next_string('$_') # None... fix it yourself
Not great. Kinda works for me.