Given a number number such that its digits are grouped into parts of length n (default value of n is 3) where each group represents some ascii value, I want to convert number into a string of those ascii characters. For example:
n number Output
==================================
3 70 F
3 65066066065 ABBA
4 65006600660065 ABBA
Note that there is no leading 0 in number, so the first ascii value will not necessarily be represented with n digits.
My current code looks like this:
def number_to_string(number, n=3):
number = str(number)
segment = []
while number:
segment.append(number[:n])
number = number[n:]
return str(''.join('{:0>{}}'.format(chr(segment), n) for segment in number))
Expected outputs:
number_to_string(70)
'F'
number_to_string(65066066065)
'ABBA'
number_to_string(65006600660065, n=4)
'ABBA'
My current code however returns an empty string. For example, instead of 'F' it returns ' '. Any reason why this is? Thank you!
P.S.:
I'm wanting to reverse the process of this question, i.e. turn an integer into a string based on the ascii values of each character (number) in the string. But reading that question is not a requirement to answer this one.
Try this:
import re
def number_to_string(num, n=3):
num_str = str(num)
if len(num_str) < n:
num_str = '0' * (n-len(num_str)) + num_str
elif len(num_str) % n != 0:
num_str = '0'*(n-len(num_str)%n) + num_str
print(num_str)
chars = re.findall('.'*n, num_str)
l = [chr(int(i)) for i in chars]
return ''.join(l)
First pad the given number (converted into string) with required number of zeros, so that it can be evenly split into equal number of characters each. Then using re split the string into segments of size n. Finally convert each chunk into character using chr, and then join them using join.
def numToStr(inp):
"""Take a number and make a sequence of bytes in a string"""
out=""
while inp!=0:
out=chr(inp & 255)+out
inp=inp>>8
print "num2string:", out
return out
does this help?
Is this what you want?
def num_to_string(num, leng):
string = ""
for i in range(0,len(str(num)),leng):
n = str(num)[i:i+2]
string += chr(int(n))
print string
Output:
>>> ================================ RESTART ================================
>>>
>>> num_to_string(650065006600,4)
AAB
>>> num_to_string(650650660,3)
AAB
>>> num_to_string(656566,2)
AAB
>>>
You can just append \x to number as this prints 'p':
print '\x70'
Related
I've just started to learn Python and I'm doing some exercises in codewars. The instructions are simple: If the string already ends with a number, the number should be incremented by 1.
If the string does not end with a number. the number 1 should be appended to the new string.
I wrote this:
if strng[-1].isdigit():
return strng.replace(strng[-1],str(int(strng[-1])+1))
else:
return strng + "1"
return(strng)
It works sometimes (for example 'foobar001 - foobar002', 'foobar' - 'foobar1'). But in other cases it adds 1 to each number at the end (for example 'foobar11' - 'foobar22'), I would like to achieve a code where the effect is to add only +1 to the ending number, for example when 'foobar99' then 'foobar100', so the number has to be considered as a whole. I would be grateful for advices for beginner :)!
First, you have to make some assumptions
Assuming that the numerical values are always at the end of string and the first character from the right that is not numeric would mark the end of the non-number string, i.e.
>>> input = "foobar123456"
>>> output = 123456 + 1
Second, we need to assume that number exists at the end of the string.
So if we encounter a string without a number, we need to decide if the python code should throw an error and not try to add 1.
>>> input = "foobar"
Or we decide that we automatically generate a 0 digit, which would require us to do something like
input = input if input[-1].isdigit() else input + "0"
Lets assume the latter decision for simplicity of the explanation.
Next we will try to read the numbers from the right until you get to a non-digit
Lets use reversed() to flip the string and then a for-loop to read the characters until we reach a non-number, i.e.
>>> s = "foobar123456"
>>> output = 123456
>>> for character in reversed(s):
... if not character.isdigit():
... break
... else:
... print(character)
...
6
5
4
3
2
1
Now, lets use a list to keep the digits characters
>>> digits_in_reverse = []
>>> for character in reversed(s):
... if not character.isdigit():
... break
... else:
... digits_in_reverse.append(character)
...
>>> digits_in_reverse
['6', '5', '4', '3', '2', '1']
Then we reverse it:
>>> ''.join(reversed(digits_in_reverse))
'123456'
And convert it into an integer:
>>> int(''.join(reversed(digits_in_reverse)))
123456
Now the +1 increment would be easy!
How do we find the string preceding the number?
# The input string.
s = "foobar123456"
s = s if s[-1].isdigit() else s + "0"
# Keep a list of the digits in reverse.
digits_in_reverse = []
# Iterate through each character from the right.
for character in reversed(s):
# If we meet a character that is not a digit, stop.
if not character.isdigit():
break
# Otherwise, keep collecting the digits.
else:
digits_in_reverse.append(character)
# Reverse, the reversed digits, then convert it into an integer.
number_str = "".join(reversed(digits_in_reverse))
number = int(number_str)
print(number)
# end of string preceeding number.
end = s.rindex(number_str)
print(s[:end])
# Increment +1
print(s[:end] + str(number + 1))
[output]:
123456
foobar
foobar123457
Bonus: Can you do it with a one-liner?
Not exactly one line, but close:
import itertools
s = "foobar123456"
s = s if s[-1].isdigit() else s + "0"
number_str = "".join(itertools.takewhile(lambda ch: ch.isdigit(), reversed(s)))[::-1]
end = s.rindex(number_str)
print(s[:end] + str(int(number_str) + 1))
Bonus: But how about regex?
Yeah, with regex it's pretty magical, you would still make the same assumption as how we started, and to make your regex as simple as possible you have to add another assumption that the alphabetic characters preceding the number can only be made up of a-z or A-Z.
Then you can do this:
import re
s = "foobar123456"
s = s if s[-1].isdigit() else s + "0"
alpha, numeric = re.match("([a-zA-z]+)(\d.+)", s).groups()
print(alpha + str(int(numeric) + 1))
But you have to understand the regex which might be a steep learning, see https://regex101.com/r/9iiaCW/1
One simple solution would be:
Have two empty variables head (=non-numeric prefix) and tail (numeric suffix). Iterate the string normally, from left to right. If the current character is a digit, add it to tail. Otherwise, join head and tail, add the current char to head and empty tail. Once complete, increment tail and return head + tail:
def foo(s):
head = tail = ''
for char in s:
if char.isdigit():
tail += char
else:
head += tail + char
tail = ''
tail = int(tail or '0')
return head + str(tail + 1)
Leading zeroes (x001 -> x002), if needed, left as an exercise ;)
In your string, you need to check if it is alpha numeric or not. if it is alpha numeric, then you need to check the last character, whether it is digit or not.
now if above condition satisfy then you need to get the index of first digit in the string which make a integer number in last of string.
once you got the index then, seperate the character and numeric part.
once done, convert numerical string part to interger and add 1. after this join both character and numeric part. that is your answer.
# your code goes here
string = 'randomstring2345'
index = len(string) - 1
if string.isalnum() and string[-1].isdigit():
while True:
if string[index].isdigit():
index-=1
else:
index+=1
break
if index<0:
break
char_part = string[:index]
int_part = string[index:]
integer = 0
if int_part:
integer = int(''.join(int_part))
modified_int = integer + 1
new_string = ''.join([char_part, str(modified_int)])
print(new_string)
output
randomstring2346
Regex can be a useful tool in python~ Here I make two groups, the first (.*?) is as few of anything as possible, while the second (\d*$) is as many digits at the end of the string as possible. For more in depth explanation see regexr.
import re
def increment(s):
word, digits = re.match('(.*?)(\d*$)', s).groups()
digits = str(int(digits) + 1).zfill(len(digits)) if digits else '1'
return word + digits
print(increment('foobar001'))
print(increment('foobar009'))
print(increment('foobar19'))
print(increment('foobar20'))
print(increment('foobar99'))
print(increment('foobar'))
print(increment('1a2c1'))
print(increment(''))
print(increment('01'))
Output:
foobar002
foobar010
foobar20
foobar21
foobar100
foobar1
1a2c2
1
02
Source
def solve(data):
result = None
if len(data) == 0 or not data[-1].isdigit():
result = data + str(1) #appending 1
else:
lin = 0
for index, ch in enumerate(data[::-1]):
if ch.isdigit():
lin = len(data) - index -1
else:
break
result = data[0 : lin] + str(int(data[lin:]) + 1) # incrementing result
return result
pass
print(solve("Hey123"))
print(solve("aaabbbzzz"))
output :
Hey124
aaabbbzzz1
I would like to separate the letters from the numbers like this
inp= "AE123"
p= #position of where the number start in this case "2"
I've already tried to use str.find() but its has a limit of 3
Extracting the letters and the digits
If the goal is to extract both the letters and the digits, regular expressions can solve the problem directly without need for indices or slices:
>>> re.match(r'([A-Za-z]+)(\d+)', inp).groups()
('AE', '123')
Finding the position of the number
If needed, regular expressions can also locate the indices for the match.
>>> import re
>>> inp = "AE123"
>>> mo = re.search(r'\d+', inp)
>>> mo.span()
(2, 5)
>>> inp[2 : 5]
'123'
You can run a loop that checks for digits:
for p, c in enumerate(inp):
if c.isdigit():
break
print(p)
Find out more about str.isdigit
this should work
for i in range(len(inp)):
if inp[i].isdigit():
p = i
break
#Assuming all characters come before the first numeral as mentioned in the question
def findWhereNoStart(string):
start_index=-1
for char in string:
start_index+=1
if char.isdigit():
return string[start_index:]
return "NO NUMERALS IN THE GIVEN STRING"
#TEST
print(findWhereNoStart("ASDFG"))
print(findWhereNoStart("ASDFG13213"))
print(findWhereNoStart("ASDFG1"))
#OUTPUT
"""
NO NUMERALS IN THE GIVEN STRING
13213
1
"""
Below is the script printing the converted octal to string. I would appreciate suggestion on how to add the - separator to the string on each permission (r/w/x)
def octal_to_string(octal):
result = ""
value_letters = [(4,"r"),(2,"w"),(1,"x")]
#Iterating over each digit in octal
for digit in [int(n) for n in str(octal)]:
#Checking for each of permission values
for value, letter in value_letters:
if digit >= value:
result += letter
digit -= value
else:
pass
return result
I currently get:
In [7]: octal_to_string(755)
Out[7]: 'rwxrxrx'
In [8]: octal_to_string(644)
Out[8]: 'rwrr'
Change the pass to result += "-":
def octal_to_string(octal):
result = ""
value_letters = [(4,"r"),(2,"w"),(1,"x")]
#Iterating over each digit in octal
for digit in [int(n) for n in str(octal)]:
#Checking for each of permission values
for value, letter in value_letters:
if digit >= value:
result += letter
digit -= value
else:
result += "-"
return result
print(octal_to_string(755))
Output:
rwxr-xr-x
For a quick fix, just replace the pass with result += '-'; for every permission test that is False you can simply insert a dash:
for value, letter in value_letters:
if digit >= value:
result += letter
digit -= value
else:
result += '-'
I'd just use bit masking however, with the & bitwise and operator:
for value, letter in value_letters:
result += letter if digit & value else '-'
This works because 4, 2 and 1 are the decimal (and octal) values for numbers with each one of the 3 bits set to 1, the others to 0. digit & 4 is only going to produce 4 or 0, depending on the value of the 3rd bit from the right being set in digit or not. Since 0 is false, and 4 is a true value, this lets you test if the right bit is set and so decide between the permission letter and -. I used a conditional expression to return either in a single line.
Next, I'd not use a list comprehension to convert the input value into octal digits; just use map() here to lazily convert without creating an additional list object:
for digit in map(int, str(octal)):
Next, try to avoid using string concatenation in a loop; although Python has some optimisations in place to avoid the worst case performance in simple situations, you can easily miss out on that optimisation. Best to append characters to a list then use str.join() to create the final string in one step.
Put together into a complete function:
def octal_to_string(octal):
result = []
for digit in map(int, str(octal)):
for value, letter in ((4, "r"), (2, "w"), (1, "x")):
result.append(letter if digit & value else "-")
return "".join(result)
Demo:
>>> octal_to_string(755)
'rwxr-xr-x'
>>> octal_to_string(644)
'rw-r--r--'
Now, what the function accepts are decimal numbers, not octal numbers. From an API design you'd really want to either accept strings only (containing digits representing an octal value), or if you do accept an integer, then you should treat that value as decimal and use 0o octal notation:
>>> 0o755 # actual octal number
493
>>> format(0o755, "o") # string representing value in octal notation
'755'
If you do so, just change str(octal) into format(octal, 'o') to get the octal digits:
>>> octal = 0o755
>>> for digit in map(int, format(octal, "o")):
... print(digit)
...
...
7
5
5
def octal_to_string(octal):
result = ""
value_letters = [(4,"r"),(2,"w"),(1,"x")]
# Iterate over each of the digits in octal
for digits in [int(n) for n in str(octal)]:
# Check for each of the permissions values
for value, letter in value_letters:
if digits >= value:
result += letter
digits -= value
else:
result += "-"
return result
Write a program that find the largest integer in a string. 'abcd51kkk3kk19ghi' would output 51.
I am having a hard time putting two digit integers into the list.
s = input('Enter a sequence of strings: ')
lst = []
for i in range(0, len(s)):
if s[i].isdigit() == True:
lst.append(s[i])
print(lst)
This problem is a good fit for regular expressions:
In [8]: max(map(int, re.findall(r'\d+', s)))
Out[8]: 51
Here, r'\d+' matches a sequence of one or more decimal digits. The matching strings are then converted to integers, and the maximum is taken.
A slightly more verbose way to write the same thing is
In [9]: max(int(digits) for digits in re.findall(r'\d+', s))
Out[9]: 51
Here's another solution, if you don't want to use regex:
s = input("Enter a sequence of strings: ")
current_num = "" # A string containing the current number that is being read
current_max = 0 # The maximum number found so far
for ch in s: # Iterate on the string, character by character
if ch.isdigit():
current_num += ch # append the digit ch to the current number
elif current_num: # if we just finished reading a number
current_max = max(int(current_num), current_max)
current_num = ""
if current_num: # in case there is no character after the last number
current_max = max(int(current_num), current_max)
print(current_max)
You can use itertools.groupby and a comprehension:
max(int(''.join(v)) for k, v in groupby(s, str.isdigit) if k)
I'm trying to create a programm in which a user inputs a string e.g 'roller' and the program converts the alphabet to numbers such as a=1, b=2, c=3 etc, and the calculate the sum of these values. But, if the program finds two same letters in a row then it doubles the sum. So far I have done this:
input = raw_input('Write Text: ')
input = input.lower()
output = []
sum=0
for character in input:
number = ord(character) - 96
sum=sum+number
output.append(number)
print sum
which calculates the sum of the characters and also appends the converted characters to a new array. So can anyone help me to double the sum if two letters appear in a row?
Store the previous character and compare it to the current character. If they're the same, double the value.
word = 'hello'
out = []
c_prev = None
for c in word:
value = ord(c) - ord('a')
if c == c_prev: # double if repeated character
value = value * 2
out.append(value)
c_prev = c # store for next comparison
print(sum(out))