How to recognise non letter from a string - python

Hi all :) I'm building a script to code text with a simple text rotation(ROT).
The script works well, but I'm having a problem, it also rotates all symbols like [spaces,!,?,.] I'm working with ascii table to do it, what can i do to avoid rotating that type of characters?
def rot13(input,key): #Function to code a text with caeser chyper.
if key > 25:
key = 25
elif key < 2:
key = 2
finaltext = ''
for letter in input:
num = ord(letter)
if (num + key) > 122: #If the final number is greater than 122..
x = (num + key) - 122
finaltext += chr(x + ord('a') - 1)
elif((num + key <= 122)):
finaltext += chr(num + key)
print(finaltext)

before "rotating" your character, add a check to see whether or not it is alphanumeric:
if letter.isalpha():
# Do your thing
else:
finaltext += letter

Try this:
>>> import string
>>> letter = 'a'
>>> letter in string.letters
True
>>> letter = '.'
>>> letter in string.letters
False

Related

How to replace each letter in a string with a consecutive letter with increasing offset?

Suppose the word is "CAT" and I want the output to be "DCW". Where the C changes to the next letter D and the A changes into the second next letter from A to C and the T changes into the third next letter from T to W.
I am on the first step here:
a = input("Enter a letter: ")
a = chr(ord(a) + 1)
print(a)
You need to loop over the word:
word = 'CAT'
result = ''
for i, a in enumerate(word,1):
result += chr(ord(a) + i)
print(result)
# alternatively, same loop as list comprehension
print(''.join(chr(ord(a) + i) for i, a in enumerate(word,1)))
Out:
DCW
DCW
What you are looking for is called Caesar cypher, but the offset changes with the character's position:
def encrypt(text):
result = ""
for i in range(len(text)):
char = text[i]
if (char.isupper()):
result += chr((ord(char) -65) % 26 + 65 + i + 1)
else:
result += chr((ord(char) - 97) % 26 + 97 + i + 1)
return result
print(encrypt(input()))
Source: https://www.tutorialspoint.com/cryptography_with_python/cryptography_with_python_caesar_cipher.htm
try this :
import string
a =input("Enter a letter: ")
r=''
for i,e in enumerate(a,1):
r=r+string.ascii_lowercase[string.ascii_lowercase.index(e.lower())+i]
print(r.upper())
or in one line like this :
print(''.join(list(string.ascii_lowercase[string.ascii_lowercase.index(e.lower())+i] for i,e in enumerate(a,1) )).upper())
Note: in Python 2, string.ascii_lowercase is string.lowercase.

Int and str changing every letter with error + EDIT: zero indexing eachword

My goal is to write a function which change every even letter into upper letter and odd to lower (space also count as a one element).
This is my code
def to_weird_case(s):
for i in s:
if len(i) % 2 == 0:
s[i] = i.upper() + s(i+1)
else:
s[i] = i.lower() + s(i+2)
return i
I think it should be quite correct, but it gives me error.
line 7, in to_weird_case
s[i] = i.lower() + s(str(i)+2)
TypeError: must be str, not int
EDIT:
I have a sugesstion but I don't know how to make it. I try it for myself and back here.
This needs to definitly explicietly state that the zero indexing uppercase is for each word.
Do you know guys how to make it?
So we can analyze your code and just explain what you typed:
def to_weird_case(s):
for i in s: # s is your string, and i is the actual character
if len(i) % 2 == 0: # if your length of the character can be divided by 2. Hmm this is weird
s[i] = i.upper() + s(i+1) # s[i] change a character in the string but you should provide an index (i) so an integer and not a character. But this is not supported in Python.
else:
s[i] = i.lower() + s(i+2)
return i # This will exit after first iteraction, so to_weird_case("this") will return "t".
So what you need to is first create a output string and fill that. And when iteration over s, you want the index of the char and the char value itself.
def to_weird_case(s):
output = ""
for i, myChar in enumerate(s):
if i % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
return output
my_sentence = "abcdef"
print(to_weird_case(my_sentence))
And when you want to ignore spaces, you need to keep track of actual characters (excluding spaces)
def to_weird_case(s):
output = ""
count = 0
for myChar in s:
if myChar.isspace():
output += myChar
else:
if count % 2 == 0:
output += myChar.upper()
else:
output += myChar.lower()
count += 1
return output
my_sentence = "abc def"
print(to_weird_case(my_sentence))
Test this yourself
def to_weird_case(s):
for i in s:
print (i)
After doing this you will find that i gives you characters.
if len(i) % 2 == 0:
This line is incorrect as you are trying to find the length of a single character. len(s) would be much better.
So the code will be like
def to_weird_case(s):
s2 = "" #We create another string as strings are immutable in python
for i in range(len(s)):
if i % 2 == 0:
s2 = s2 + s[i].upper()
else:
s2 = s2 + s[i].lower()
return s2
From #RvdK analysis, you'ld have seen where corrections are needed. In addition to what has been pointed out, I want you to note that s[i] will work fine only if i is an integer, but in your case where (by assumption) i is a string you'll encounter several TypeErrors. From my understanding of what you want to do, it should go this way:
def to_weird_case(s):
for i in s:
if s.index(i) % 2 == 0:
s[s.index(i)] = i.upper() + s[s.index(i)]
elif s.index(i) % 2 == 1:
s[s.index(i)] = i.lower() + s[s.index(i)]
return i # or possibly return s
It is possible to do in a single line using a list comprehension
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s)])
If you want to treat each word separately then you can split it up in to a list of words and "funny case" each word individually, see below code
original = "hello world"
def funny_case(s):
return "".join([c.upper() if idx%2==0 else c.lower() for idx,c in enumerate(s) ])
def funny_case_by_word(s):
return " ".join((funny_case(word) for word in s.split()))
print(funny_case_by_word(original))
Corrected code is as follows
def case(s):
txt=''
for i in range(len(s)):
if i%2==0:
txt+=s[i].upper()
else:
txt+=s[i].lower()
return txt
String assignment gives error in Python therefore i recommend considering my approach
When looping over elements of s, you get the letter itself, not its index. You can use enumerate to get both index and letter.
def to_weird_case(s):
result = ''
for index, letter in enumerate(s):
if index % 2 == 0:
result += letter.upper()
else:
result += letter.lower()
return result
correct code:
def to_weird_case(s):
str2 = ""
s.split() # through splitting string is converted to list as it is easy to traverse through list
for i in range(0,len(s)):
n = s[i] # storing value in n
if(i % 2 == 0):
str2 = str2 + n.upper()
else:
str2 = str2 + n.lower()
return str2
str1 = "hello world"
r = to_weird_case(str1)
print(r)

How to create a circular Alphabet in Python so that the letter after z is a and the letter before a is z

Is there a Function in Python to easily create a circular Alphabet, so that the letter after z is a and the letter before a is z?
I tried something with chr() and .join(Alphabet), but that didn't worked because i got the error message an integer is required (got type str).
for character in word:
if chr(Alphabet[Alphabet.find(character)) >= "z":
new_Alphabet = Alphabet.join(Alphabet)
elif chr(Alphabet[Alphabet.find(character)) <= "a":
new_Alphabet = Alphabet.join(Alphabet[:-1])
Use itertools.cycle ans string.ascii_lowercase:
from itertools import cycle
import string
circular_alphabet = cycle(string.ascii_lowercase)
That is an infinite iterator with the lowercase letters:
>>> "".join(next(circular_alphabet ) for _ in range(50))
'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx'
I think you have to use circular queue. for more information please check this link.
Alternative (old fashion?) solution:
def cycle_letter(ch,up=True):
upper = 'A' <= ch <= 'Z'
ch = ch.lower()
letters = 'abcdefghijklmnopqrstuvwxyz'
pos = letters.find(ch)
if pos < 0: return ch
length = len(letters)
pos += 1 if up else length-1
ans = letters[pos%length]
if upper: ans = ans.upper()
return ans
################################################################################
def cycle_string(s,up=True):
return ''.join(cycle_letter(ch,up) for ch in s)
################################################################################
if __name__ == '__main__': #Test
s = cycle_string('Hello, World!')
print(s)
s = cycle_string(s,False)
print(s)
In case it helps someone, this snippet shifts a word by the desired number of spaces. (e.g. shift_word('abcdef', 12) = 'opqrst' )
def shift_word(word: str, spaces: int) -> str:
first_ordinal = 97
last_ordinal = 122
alphabet_size = 26
return ''.join(chr((ord(letter) - last_ordinal - spaces - 1) % alphabet_size + first_ordinal) for letter in word)
It simply iterates over the word letter-by-letter, applies some modulo math to calculate the right "bucket" where the letter should fall, and makes sure the result is in the boundaries of ordinals 97-122 (letters a-z)

Letter Change using Python

Problem statement:
Have the function LetterChanges(str) take the str parameter being passed and modify it using the following algorithm. Replace every letter in the string with the letter following it in the alphabet (ie. c becomes d, z becomes a). Then capitalize every vowel in this new string (a, e, i, o, u) and finally return this modified string.
My Python program is:
def LetterChanges(str):
for i in range(0,len(str)):
a=ord(str[i])
if a==122:
str=str.replace(str[i],'a',1)
elif a==90:
str=str.replace(str[i],'a',1)
elif (a>=65 and a<=90) or (a>=97 and a<=122):
a=a+1
char=chr(a)
str=str.replace(str[i],char,1)
for i in range(0,len(str)):
if str[i]=='a':
str=str.replace(str[i],'A',1)
elif str[i]=='e':
str=str.replace(str[i],'E',1)
elif str[i]=='i':
str=str.replace(str[i],'I',1)
elif str[i]=='o':
str=str.replace(str[i],'O',1)
elif str[i]=='u':
str=str.replace(str[i],'U',1)
return(str)
print LetterChanges(raw_input())
The problem with my code is that, when I input sen, the output was tfo which was correct.
But when I gave sent as my input, I got the wrong output.
Your mistake is here :silpa
when you are replacing you have not cared about indices where character is replacing so how it is going when you give sent input
after replacing n we get string like tfot now in next iteration next letter you encounter in your original string is t so it will replace the first letter that is t in the replaced string so . "tfot" becomes "ufot" and last t is not being replaced
here an another try :
def prgrm(n):
k = ""
for i in n:
nxt = chr(97 if i == 'z' else ord(i)+1)
if nxt in ('a', 'e', 'i', 'o', 'u'):
nxt = nxt.capitalize()
k += nxt
print(k)
prgrm('sen')
A functional programming take, without using ord() or a loop, will work with presence of other non alphabetic characters I think:
def LetterChanges(str):
vowels = "aeiou"
lowers = "abcdefghijklmnopqrstuvwxyza"
all = lowers.upper() + lowers
# Map all alphabetical characters
nxt_str = "".join(map(lambda x: all[all.index(x) + 1] if x in all else x, str))
# Map the vowels
return "".join(map(lambda x: x.upper() if x in vowels else x, nxt_str))
print(LetterChanges("sentdZ"))
tfOUEA
You are processing the 't' twice in your string, first the s is replaced by 't' and after that 't' is replaced again by 'u' also the first replacement in the string
def LetterChanges(line):
result = ""
for i in line:
a=ord(i)
if a == 122 or a == 90:
result += 'A'
elif (a >= 65 and a <= 90) or (a >= 97 and a <= 122):
a = a + 1
char = chr(a)
if char in ('e', 'i', 'o', 'u'):
char = char.upper()
result += char
else:
result += i
return(result)
Here is another way with using re:
import re
def letter_changes(my_string):
in_letters = "abcdefghijklmnopqrstuvxyz"
out_letters = "bcdefghijklmnopqrstuvxyza"
letter_dict1 = {x:y for x,y in zip(in_letters, out_letters)}
letter_dict2 = {'a':'A', 'e':'E', 'i':'I', 'o':'O', 'u':'U'}
for l_dict in [letter_dict1, letter_dict2]:
pattern = re.compile("|".join(l_dict.keys()))
my_string = pattern.sub(lambda m: l_dict[re.escape(m.group(0))], my_string)
return my_string
This is another way to write your code:-
def rep_cap(sent):
sent_rp = ''.join([chr(c) for c in [x+1 for x in [ord(c) for c in sent]]]).replace('{','a') #This thing is done to convert a to b .... z to a
final_output = ""
vowels = ['a','e','i','o','u']
for i in sent_rp:
if i in vowels:
final_output = final_output+i.upper() #convert vowels to upper case
else :
final_output = final_output+i
return final_output
sent = raw_input("Enter a sentence:")
print rep_cap(sent)
replace this line
str=str.replace(str[i],char,1) with
str = str[:i] + char + str[i+1:]
Reason for this problem answered by #Pankaj78691 is correct!!
Here is my version of the algorithm.
def LetterChanges(str):
result = ''
vowels = ['a','e','i','o','u']
for s in str:
if s.isalpha():
if ord(s) == 122: #ASCII code of 'z'
next_letter = chr(97)
else:
next_letter = chr(ord(s)+1)
if next_letter in vowels:
result += next_letter.upper()
else:
result += next_letter
else:
result += s
return result

Python skipping my if statement

For some reason, this code doesn't work:
def pyglatin(word):
output = ""
wordlenedit = len(word)-1
wordlen = len(word)
fixer = 0
while fixer == 0:
for i in word:
if i == 'a' or i == 'e' or i == 'o' or i == 'i' or i == 'u':
fixer = 1
else:
wordlenedit -= 1
else:
output = word[wordlenedit:wordlen:1] + '-' + word[0:wordlenedit:1] + 'ay'
return output
To see the issues, click here. The problem appears to be that it's skipping the if statement that identifies vowels, but I'm not sure why. This results in some very odd outputs.
Your function does not work because you walk through the word, decrementing the splitting index for each consonant you encounter, starting at wordlenedit = len(word)-1.
At the end of your for loop, wordlenedit is equal to (length of the word) - 1 - (number of consonants). The function will only work if the first index of vowel in the word (starting at 0) is equal to the number of vowels - 1.
Also, the while loop is useless here, as you walk through the entire word in the for loop. It is even worse than that: the while loop will be an infinite loop if you have a word with no vowels (like "fly", as you don't check the "y")
This is a corrected version of your function, using the keyword break:
def pyglatin2(word):
output = ""
wordlenedit = 0
wordlen = len(word)
for l in word:
if l == 'a' or l == 'e' or l == 'o' or l == 'i' or l == 'u':
break
else:
wordlenedit += 1
output = word[wordlenedit:wordlen:1] + '-' + word[0:wordlenedit:1] + 'ay'
return output
However this function can be written in a much more concise/simple way, using Regular Expressions, like this:
import re
def pyglatin3(word):
# Get the first index of one of these: a, e, i, o, u
start = re.search("[aeiou]", word).start()
# Split the word
return word[start:] + "-" + word[0:start] + "ay"
If you want to do this without using regular expressions, the simplest way is to use enumerate:
def pyglatin(word):
for i, ch in enumerate(word):
if ch in 'aeiou':
return word[i:] + '-' + word[:i] + 'ay'

Categories