moving integers from one string to another? - python

I am looking at adding numbers to a string as python reads through a string.
So if I had a string a = "253+"
I would then have an empty string b.
So, how would I have python read the 2, add it to string b, then read the 5 and add it to string b, and then add the 5 and add it to string b, when it hits something that isnt an integer though, it stops the function.
then string b would be b = "253"
is there a specific call in an iteration that would ask for integers and then add i to another string?
tl;dr
I want to use an iteration to add numbers from one string to another, which stops when it reaches a non-integer.
string b would be an empty string, and string a would be a="253+"
after the call would be done, strng b would equal b="253"
I know this sounds like a homework question, but its not. If you need anything else clarified, I would be happy to.

Here is a simple method for extracting the digits from a string:
In [13]: a="253+"
In [14]: ''.join(c for c in a if c.isdigit())
Out[14]: '253'

The question is a bit unclear, but is this what you're looking for?
a = "123+"
b=""
for c in a:
try:
int(c)
b = b + c
except ValueError:
print 'This is not an int ' + c
break
Running this results in this b being 123 and breaking on the + character. It sounds like the part that's tricky for you at the moment is the try..except ValueError bit. Not that I don't have to break the loop when a ValueError happens, I could just keep looping over the remaining characters in the string and ignore ones that cannot be parsed into an int

In [201]: import itertools as IT
In [202]: a = "253+9"
In [203]: ''.join(IT.takewhile(str.isdigit, a))
Out[203]: '253'
IT.takewhile will stop at the first character in a which is not a digit.
Another way would be to use a regex pattern. You could split the string on non-digits using the pattern r'\D':
In [208]: import re
In [209]: re.split(r'\D', a, maxsplit=1)[0]
Out[209]: '253'

With the use of the for loop, this is relatively easy. If we use our ASCII knowledge, we know that the ASCII values of the digits range from 48 (which represents 0 as a string) to 57 (which represents 9 as a string).
We can find the ASCII value of a character by using the built in method ord(x) where x is the character (i.e. ord('4') is equal to 52, the integer).
Now that we have this knowledge, it will be easy to add this to our for-loop. We simply make a for-loop that goes from 0 to the length of the string minus 1. In the for loop, we are going to use the iteration that we are on as an index, find the character at that index in our string, and finally check to see if its ord value falls in the range that we want.
This will look something like this:
def method(just_a_variable):
b = ''
for i in range(0, len(a)):
if (#something):
if (#something):
b = b+a[i]
return b
Can you fill in the "#somethings"?

Try this:
a = "i889i" #Initial value of A
b = "" #Empty string to store result into
for each in a: #iterate through all characters of a
if each.isdigit(): #check if the current character is a digit
b += each #append to b if the current character is a digit
else: #if current character is NOT a digit
break #break out of for loop
print b #print out result
Hope this helps!

You can write a generator with a regex and generate them one by one:
>>> import re
>>> s='123+456abc789'
>>> nums=(m.group(1) for m in re.finditer(r'(\d+)', s))
>>> next(nums)
'123'
>>> next(nums)
'456'
>>> next(nums)
'789'

Related

Slicing where stop is larger than the string length

I'm interested in how is Python handling slicing where the stop attribute is larger than the length of the string we are working with, for example:
my_string = 'abc'
my_slice = my_string[:10]
I am aware that my_slice == 'abc', what interests me is how efficient this is and how it works under the hood.
I've read Time complexity of string slice and Understanding slice notation, but didn't find the exact case I was looking for.
My guess based on mentioned sources would be that a shallow copy of the string is returned (my_string[:10] is the same as my_string[:] in this case), is this the case?
The logic of python is that it will extract all the values that are before that index in the list.
So if the stop value is higher than the length of the list it will return the whole list because all the values' indexes are under the stop number, so it will extract all the values.
Slicing in Python follows the following format:
myVar[fromIndex:toIndex]
The end of the slicing marked by the toIndex, counts to its index, which is one character less:
my_string = 'abc'
print(my_string[2]) #Output: 'c'
print(my_string[:2]) #Output: 'ab'
If we set a final index greater than the length of characters of the data, it will take it entire (it prints from the first value to the last one found). For example (following the example you have given):
0 1 2 3
a b c
my_string = 'abc'
print(my_string[:len(my_string)]) #Output: 'abc'
With the following example, you can clearly see that [:] (being the full length of the string) is equivalent to printing the value by slicing from the beginning to the end of the string:
0 1 2
a b c
my_string = 'abc'
print(my_string[:]) #Output: 'abc'
0 1 2 3
a b c
my_string = 'abc'
print(len(my_string)) #Output: '3'
print(my_string[:len(my_string)]) #Output: 'abc'

How does comparing two chars (within a string) work in Python

I am starting to learn Python and looked at following website: https://www.w3resource.com/python-exercises/string/
I work on #4 which is "Write a Python program to get a string from a given string where all occurrences of its first char have been changed to '$', except the first char itself."
str="restart"
char=str[0]
print(char)
strcpy=str
i=1
for i in range(len(strcpy)):
print(strcpy[i], "\n")
if strcpy[i] is char:
strcpy=strcpy.replace(strcpy[i], '$')
print(strcpy)
I would expect "resta$t" but the actual result is: $esta$t
Thank you for your help!
There are two issues, first, you are not starting iteration where you think you are:
i = 1 # great, i is 1
for i in range(5):
print(i)
0
1
2
3
4
i has been overwritten by the value tracking the loop.
Second, the is does not mean value equivalence. That is reserved for the == operator. Simpler types such as int and str can make it seem like is works in this fashion, but other types do not behave this way:
a, b = 5, 5
a is b
True
a, b = "5", "5"
a is b
True
a==b
True
### This doesn't work
a, b = [], []
a is b
False
a == b
True
As #Kevin pointed out in the comments, 99% of the time, is is not the operator you want.
As far as your code goes, str.replace will replace all instances of the argument supplied with the second arg, unless you give it an optional number of instances to replace. To avoid replacing the first character, grab the first char separately, like val = somestring[0], then replace the rest using a slice, no need for iteration:
somestr = 'restart' # don't use str as a variable name
val = somestr[0] # val is 'r'
# somestr[1:] gives 'estart'
x = somestr[1:].replace(val, '$')
print(val+x)
# resta$t
If you still want to iterate, you can do that over the slice as well:
# collect your letters into a list
letters = []
char = somestr[0]
for letter in somestr[1:]: # No need to track an index here
if letter == char: # don't use is, use == for value comparison
letter = '$' # change letter to a different value if it is equal to char
letters.append(letter)
# Then use join to concatenate back to a string
print(char + ''.join(letters))
# resta$t
There are some need of modification on your code.
Modify your code with as given in below.
strcpy="restart"
i=1
for i in range(len(strcpy)):
strcpy=strcpy.replace(strcpy[0], '$')[:]
print(strcpy)
# $esta$t
Also, the best practice to write code in Python is to use Function. You can modify your code as given below or You can use this function.
def charreplace(s):
return s.replace(s[0],'$')[:]
charreplace("restart")
#'$esta$t'
Hope this helpful.

Python find position of last digit in string

I have a string of characters with no specific pattern. I have to look for some specific words and then extract some information.
Currently I am stuck at finding the position of the last number in a string.
So, for example if:
mystring="The total income from company xy was 12320 for the last year and 11932 in the previous year"
I want to find out the position of the last number in this string.
So the result should be "2" in position "70".
You can do this with a regular expression, here's a quick attempt:
>>>mo = re.match('.+([0-9])[^0-9]*$', mystring)
>>>print mo.group(1), mo.start(1)
2 69
This is a 0-based position, of course.
You can use a generator expression to loop over the enumerate from trailing within a next function:
>>> next(i for i,j in list(enumerate(mystring,1))[::-1] if j.isdigit())
70
Or using regex :
>>> import re
>>>
>>> m=re.search(r'(\d)[^\d]*$',mystring)
>>> m.start()+1
70
Save all the digits from the string in an array and pop the last one out of it.
array = [int(s) for s in mystring.split() if s.isdigit()]
lastdigit = array.pop()
It is faster than a regex approach and looks more readable than it.
def find_last(s):
temp = list(enumerate(s))
temp.reverse()
for pos, chr in temp:
try:
return(pos, int(chr))
except ValueError:
continue
You could reverse the string and get the first match with a simple regex:
s = mystring[::-1]
m = re.search('\d', s)
pos = len(s) - m.start(0)

confused about max() built in function

hello I am kind of confused about the max() function, I have the following code:
a = '9:30'
b = '10:44'
c = '8:22'
x = max(a, b, c)
print (x)
so my question is: why does this return 9:30? and if I were to delete the a from inside max it would return 8:22
String a compares as the biggest because it starts with 9 and the other strings start with 1 and 8. Python therefore returns '9:30' as the maximum value out of those three strings.
As you are doing string comparison the int or ASCII value of '9' is greater than '8' and '1'. You can see the int value of individual char using ord built-in function.
>>> ord('9')
57
>>> ord('1')
49
>>> ord('8')
56
And as Python does comparison in lexicographical manner(from left to right each char). It finds value of '9' greater. And if you delete '9' if finds '8''s value greater than '1'.
One way to achieve could be :-
a = '9:30'
b = '10:44'
c = '8:22'
d = '10:55'
print max([a, b, c, d], key=lambda x: map(int, x.split(':')))
Its because of that max function will find the max value lexicographicaly , you can use a proper key for max function to convert the hour and min to int.
>>> l=[a,b,c]
>>> max(l,key=lambda d :map(int, d.split(":")))
'10:44'
Since it's arguments are strings, it is returning the string that is latest in alphabetic order.
it is comparing strings, and, as such, it starts by comparing the first character, and then, if that character is the same, moves on to the next and then the next etc etc.
So '9:30' is returned because 9 > 8 > 1. If you want "10:44" to return, then you should use the datetime module, unless you want to write custom code for that
edit: and sniped by people who type faster!
You are comparing strings, not numbers or times. As such, it compares the strings by their first character (and if those are equal, by the second, and so on), and the first character of "9:30" is the highest.
If you want to compare the times, you can split the string at the :symbol, map the parts to integers and compare those, using an according key function.
x = max([a, b, c], key=lambda s: map(int, s.split(":")))
Here's another way to do it so you can just use the regular max function. First, pad the strings so that "9" becomes "09" and "10" stays "10". You can use str.zfill for this:
a = '9:30'
b = '10:44'
c = '8:22'
a, b, c = map(lambda s: s.zfill(5), (a, b, c))
Now, they will be what you want lexicographically!
print(max([a, b, c]))
10:44
You only have to pad them once, but you will be stuck with:
print(min([a, b, c]))
08:22

Swapping every second character in a string in Python

I have the following problem: I would like to write a function in Python which, given a string, returns a string where every group of two characters is swapped.
For example given "ABCDEF" it returns "BADCFE".
The length of the string would be guaranteed to be an even number.
Can you help me how to do it in Python?
To add another option:
>>> s = 'abcdefghijkl'
>>> ''.join([c[1] + c[0] for c in zip(s[::2], s[1::2])])
'badcfehgjilk'
import re
print re.sub(r'(.)(.)', r'\2\1', "ABCDEF")
from itertools import chain, izip_longest
''.join(chain.from_iterable(izip_longest(s[1::2], s[::2], fillvalue = '')))
You can also use islices instead of regular slices if you have very large strings or just want to avoid the copying.
Works for odd length strings even though that's not a requirement of the question.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
Here's a nifty solution:
def swapem (s):
if len(s) < 2: return s
return "%s%s%s"%(s[1], s[0], swapem (s[2:]))
for str in ("", "a", "ab", "abcdefgh", "abcdefghi"):
print "[%s] -> [%s]"%(str, swapem (str))
though possibly not suitable for large strings :-)
Output is:
[] -> []
[a] -> [a]
[ab] -> [ba]
[abcdefgh] -> [badcfehg]
[abcdefghi] -> [badcfehgi]
If you prefer one-liners:
''.join(reduce(lambda x,y: x+y,[[s[1+(x<<1)],s[x<<1]] for x in range(0,len(s)>>1)]))
Here's a another simple solution:
"".join([(s[i:i+2])[::-1]for i in range(0,len(s),2)])

Categories

Resources