I have this python function here. However when running I'm getting an error "could not convert string to float: '$50.50'". I need to add the input as a string including the "$" sign and then convert it to a float number in the backend. The function seems to work adding only "50.50" as input.
def main():
dollars = dollars_to_float(input("How much was the meal? "))
percent = percent_to_float(input("What percentage would you like to tip? "))
tip = dollars * percent/100
print(f"Leave $" , str(tip) )
def dollars_to_float(d):
str.lstrip(d)
return float(d)
def percent_to_float(p):
str.rstrip(p)
return float(p)
main()
Error:
File "/Users/nelsonlamounier/indoor/indoor.py", line 13, in <module>
main()
File "/Users/nelsonlamounier/indoor/indoor.py", line 9, in dollars_to_float
return float(d)
File "/Users/nelsonlamounier/indoor/indoor.py", line 9, in dollars_to_float
return float(d)
ValueError: could not convert string to float: '$50.50'
For a more general case, update dollars_to_float with the following:
def dollars_to_float(d):
d = ''.join([ch for ch in d if ch.isnumeric() or ch == '.'])
return float(d)
Just remove $ before number like:
def dollars_to_float(d):
str.lstrip(d)
return float(d.replace("$",""))
Your code is error prone, as a single space character would already be able to break it. A more robust version of the currency to float conversion can be found here Remove currency symbols and literals from a string with a price universal solution
You use locale to see what is the decimal point character (, or .), and regex to remove all characters other than numerals and the decimal point.
import re
import locale
def dollars_to_float(price_string: str) -> float:
decimal_point_char = locale.localeconv()['decimal_point']
clean = re.sub(r'[^0-9'+decimal_point_char+r']+', '', str(price_string))
return float(clean)
If you want to remove specific characters from the beginning or end of a string then use strip()
In this case your dollars_to_float and percent_to_float could be generalised to:
def to_float(d):
return float(d.strip('$%'))
This has the advantage of supporting the $ and % characters at either the beginning or end of the string.
However, say the input is like this '$1,200'
That's going to fail due to the thousands separator. Also, why limit functionality to just dollars. Why not allow for an arbitrary preamble to the input string - e.g., USD1,200 or £1,234,50
Here's a reasonably robust approach to this problem.
import re
from locale import LC_NUMERIC, setlocale, localeconv
class CC:
dp = None
def __init__(self):
if CC.dp is None:
setlocale(LC_NUMERIC, '')
dp = localeconv()['decimal_point']
CC.dp = f'[^0-9{dp}+-]+'
def conv(self, s):
return float(re.sub(CC.dp, '', s))
print(CC().conv('$1,200.5'))
print(CC().conv('£1,200'))
print(CC().conv('EUR1234.5'))
print(CC().conv('6543.21'))
Output:
1200.5
1200.0
1234.5
6543.21
Related
When I try to convert big numbers I get extra numbers at the end that doesn't move plus an L character too. How to remove the 4 extra characters at the end 000L?
8b8dbbc584d9c000L
8b8dc4ddd34c6000L
8b8dcdf621bf0000L
8b8dd70e7031a000L
8b8de026bea44000L
#!/usr/bin/python
import sys
def int_tuple_from_cmdline():
"""return exactly two integers form sys.argv
or die with an error message
"""
import sys
args = sys.argv[1:] # drop first entry (progpath)
if len(args) != 2:
raise SystemExit("\n#################################################\n# Please enter both a
start and stop parameter. #\n#################################################")
for i in range(len(args)):
try:
args[i] = int(args[i])
except ValueError:
raise SystemExit("\n#################################################\n# Parameter %d is not an integer. You entered: %s #\n#################################################\n" %(i+1,args[i]))
return tuple(args)
start, stop = int_tuple_from_cmdline()
r = start - 10000000000000
while r < stop:
r = r + 50000000000000
hx = hex(r)[2:]
print(hx)
If what you're after is simply removing the last four characters of a string, you can use slicing to perform it:
s = "8b8dbbc584d9c000L"
trimmed = s[:-4] #8b8dbbc584d9c
Note that it will produce an empty string if the original string doesn't have at least four characters.
Also note that my answer has nothing to do with conversion from decimal to hex per se, I'm just answering the trimming part of it.
I have to use python to read a file, this file contains combination of characters, numbers and other stuff.
After reading a single line from the file, how do I check if this line is an integer or a float? (I have to know this information that this line is an integer and float)
I have tried these string methods .isdigit(), .isdecimal(), .isnumeric(), it seems like these methods only return True when there are only all decimal numbers within the string.
Is there any method that can help me to do this task?
P.S.: Can't use try or any exception approach.
============== Content of my File =================
0
[Begin Description]
xxx
[End Description]
1.1
[Begin Description]
....
I want to know if the current line I am reading is integer 0 or float 1.1. That makes my question.
I hope this will help
import re
s = "1236.0"
r = re.compile(r'[1-9]')
r2 = re.compile(r'(\.)')
if re.search(r,s) and re.search(r2,s):
print("Float")
if re.search(r,s) and not re.search(r2,s):
print("Integer")
You should use try and except:
But if you dont want to use it and need different way then use regex:
if re.match(r"[-+]?\d+(\.0*)?$", s):
print("match")
For each line in the file you can check with regex whether it is a float or int or normal string
import re
float_match = re.compile("^[-+]?[0-9]*[.][0-9]+$")
int_match = re.compile("^[-+]?[0-9]+$")
lines = ["\t23\n", "24.5", "-23", "0.23", "-23.56", ".89", "-122", "-abc.cb"]
for line in lines:
line = line.strip()
if int_match.match(line):
print("int")
elif float_match.match(line):
print("float")
else:
print("str")
Result:
int
float
int
float
float
float
int
str
How it works:
int_match = re.compile("^[-+]?[0-9]+$")
^: at the str beginning
[-+]?: optional + or -
[0-9]+: one or more numbers
$: end of string
float_match = re.compile("^[-+]?[0-9]*[.][0-9]+$")
^[-+]?: start with either + or - optional.
[0-9]*: any number of digits or none.
[.]: dot
[0-9]+: one or more digits
$:end
This is faster than re
although this is not type checking but as you are reading string 0 or 1.1 you can do simply like
line='1.1'
if '.' in line:
print("float")
else:
print("int")
Try this :
import re
line1 = '0'
line2 = 'description one'
line3 = '1.1'
line4 = 'begin description'
lines = [line1, line2, line3, line4] # with readlines() you can get it directly
for i in lines:
if re.findall("[+-]?\d+", i) and not re.findall("[+-]?\d+\.\d+", i):
print('int found')
elif re.findall("[+-]?\d+\.\d+", i):
print('float found')
else:
print('no numeric found')
OUTPUT :
int found
no numeric found
float found
no numeric found
You could split it into words using .split() and use string methods.
Example Code (Note that split method argument should be changed to comma if you use it in floats instead of dot):
def float_checker(strinput):
digit_res = None
for part in strinput.split('.'):
digit_res = True if part.isnumeric() else False
if digit_res:
return True
return False
if __name__ == '__main__':
while True:
print(float_checker(input('Input for float check (Stop with CTRL+C): ')))
I wrote a code that will generate random password for 5 times, and I would like to encode that passwords to MD5, but when I try to encode it, it will show an error that 'NoneType' object has no attribute 'encode' and I dont know how to change the code to avoid this error. Sorry I'm beginner in python... My Code is below. Thanks for help
import random, string
import hashlib
length = 6
chars = string.ascii_letters + string.digits
def ff():
rnd = random.SystemRandom()
a = (''.join(rnd.choice(chars) for i in range(length)))
c = a
return(c)
def ff2():
for i in range(5):
print(ff(),' ')
str = ff2()
result = hashlib.md5(str.encode())
print("The hexadecimal equivalent of hash is : ", end ="")
print(result.hexdigest())
The function ff2 doesn’t return anything so str will be of type NoneType.
IIUC, your ff2() function should call ff() five times but it should not print out the result. It should accumulate them in a string and return the string. Something like this perhaps:
def ff2():
l = []
for i in range(5):
l.append(ff())
return " ".join(l)
Here we accumulate the results of the five calls to ff() in a list l and then
use the string method join() to join them together.
The above returns a string that is the concatenation of the five strings that the calls to ff() returned, with spaces separating them. If you want commas as separators, just replace the return " ".join(l) with return ",".join(l).
I have a file full of strings which i read into a list. Now I'd like to find a specific line (for example the first line below) by looking for .../002/... and add to these 002 +5 to give me /007/, in order to find my next line containing /007/.
The file looks like this
https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/6/MYD021KM/2018/002/MYD021KM.A2018002.1345.006.2018003152137.hdf
https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/6/MYD021KM/2018/004/MYD021KM.A2018004.1345.006.2018005220045.hdf
with this i could identify for example the first line:
match = re.findall("/(\d{3})/", data_time_filtered[i])
The problem now is: how do I convert the string to integers but keeping the format 00X? Is this Ansatz correct?:
match_conv = ["{WHAT's in HERE?}".format(int(i)) for i in match]
EDIT according to suggested answers below:
So apparently there's no way to directly read the numbers in the string and keep them as they are?
adding 0s to the number with zfill and other suggested functions makes it more complicated as /00x/ should remain max 3 digits (as they represent days of year). So i was looking for an efficient way to keep the numbers from the string as they are and make them "math-able".
We can first define a function that adds a integer to a string and returns a string, padded with zeros to keep the same length:
def add_to_string(s, n):
total = int(s)+n
return '{:0{}}'.format(total, len(s))
add_to_string('003', 2)
#'005'
add_to_string('00030', 12 )
#'00042
We can then use re.sub with a replacement function. We use the regex r"(?<=/)\d{3}(?=/)" that matches a group of 3 digits, preceded and followed by /, without including them in the match.
The replacement function takes a match as parameter, and returns a string.You could hardcode it, like this:
import re
def add_5_and_replace(match):
return add_to_string(match.group(0), 5)
url = 'https://nasa.gov/archive/allData/6/MYD021KM/2018/002/MYD021KM.hdf'
new = re.sub(r"(?<=/)\d{3}(?=/)", add_5_and_replace, url)
print(new)
# https://nasa.gov/archive/allData/6/MYD021KM/2018/007/MYD021KM.hdf
But it could be better to pass the value to add. Either use a lambda:
def add_and_replace(match, n=1):
return add_to_string(match.group(0), n)
url = 'https://nasa.gov/archive/allData/6/MYD021KM/2018/002/MYD021KM.hdf'
new = re.sub(r"(?<=/)\d{3}(?=/)", lambda m: add_and_replace(m, n=5), url)
Or a partial function. A complete solution could then be:
import re
from functools import partial
def add_to_string(s, n):
total = int(s)+n
return '{:0{}}'.format(total, len(s))
def add_and_replace(match, n=1):
return add_to_string(match.group(0), n)
url = 'https://nasa.gov/archive/allData/6/MYD021KM/2018/002/MYD021KM.hdf'
new = re.sub(r"(?<=/)\d{3}(?=/)", partial(add_and_replace, n=3), url)
print(new)
# https://nasa.gov/archive/allData/6/MYD021KM/2018/005/MYD021KM.hdf
If you only want to add the default value 1 to your number, you can simply write
new = re.sub(r"(?<=/)\d{3}(?=/)", add_and_replace, url)
print(new)
# https://nasa.gov/archive/allData/6/MYD021KM/2018/003/MYD021KM.hdf
Read about mini format language here:
c = "{:03}".format(25) # format a number to 3 digits, fill with 0
print(c)
Output:
025
You can't get int to be 001, 002. They can only be 1, 2.
You can do similar by using string.
>>> "3".zfill(3)
'003'
>>> "33".zfill(3)
'000ss'
>>> "33".rjust(3, '0')
'033'
>>> int('033')
33
>>> a = 3
>>> a.zfill(3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute 'zfill'
Or you rjust and ljust:
>>> '2'.ljust(3,'0')
'200'
>>> '2'.rjust(3,'0')
'002'
>>>
Or:
>>> '{0:03d}'.format(2)
'002'
Or:
>>> format(2, '03')
'002'
Or:
>>> "%03d" % 2
'002'
I'm pretty new to Python programming and would appreciate some help to a problem I have...
Basically I have multiple text files which contain velocity values as such:
0.259515E+03 0.235095E+03 0.208262E+03 0.230223E+03 0.267333E+03 0.217889E+03 0.156233E+03 0.144876E+03 0.136187E+03 0.137865E+00
etc for many lines...
What I need to do is convert all the values in the text file that are less than 1 (e.g. 0.137865E+00 above) to an arbitrary value of 0.100000E+01. While it seems pretty simple to replace specific values with the 'replace()' method and a while loop, how do you do this if you want to replace a range?
thanks
I think when you are beginning programming, it's useful to see some examples; and I assume you've tried this problem on your own first!
Here is a break-down of how you could approach this:
contents='0.259515E+03 0.235095E+03 0.208262E+03 0.230223E+03 0.267333E+03 0.217889E+03 0.156233E+03 0.144876E+03 0.136187E+03 0.137865E+00'
The split method works on strings. It returns a list of strings. By default, it splits on whitespace:
string_numbers=contents.split()
print(string_numbers)
# ['0.259515E+03', '0.235095E+03', '0.208262E+03', '0.230223E+03', '0.267333E+03', '0.217889E+03', '0.156233E+03', '0.144876E+03', '0.136187E+03', '0.137865E+00']
The map command applies its first argument (the function float) to each of the elements of its second argument (the list string_numbers). The float function converts each string into a floating-point object.
float_numbers=map(float,string_numbers)
print(float_numbers)
# [259.51499999999999, 235.095, 208.262, 230.22300000000001, 267.33300000000003, 217.88900000000001, 156.233, 144.876, 136.18700000000001, 0.13786499999999999]
You can use a list comprehension to process the list, converting numbers less than 1 into the number 1. The conditional expression (1 if num<1 else num) equals 1 when num is less than 1, otherwise, it equals num.
processed_numbers=[(1 if num<1 else num) for num in float_numbers]
print(processed_numbers)
# [259.51499999999999, 235.095, 208.262, 230.22300000000001, 267.33300000000003, 217.88900000000001, 156.233, 144.876, 136.18700000000001, 1]
This is the same thing, all in one line:
processed_numbers=[(1 if num<1 else num) for num in map(float,contents.split())]
To generate a string out of the elements of processed_numbers, you could use the str.join method:
comma_separated_string=', '.join(map(str,processed_numbers))
# '259.515, 235.095, 208.262, 230.223, 267.333, 217.889, 156.233, 144.876, 136.187, 1'
typical technique would be:
read file line by line
split each line into a list of strings
convert each string to the float
compare converted value with 1
replace when needed
write back to the new file
As I don't see you having any code yet, I hope that this would be a good start
def float_filter(input):
for number in input.split():
if float(number) < 1.0:
yield "0.100000E+01"
else:
yield number
input = "0.259515E+03 0.235095E+03 0.208262E+03 0.230223E+03 0.267333E+03 0.217889E+03 0.156233E+03 0.144876E+03 0.136187E+03 0.137865E+00"
print " ".join(float_filter(input))
import numpy as np
a = np.genfromtxt('file.txt') # read file
a[a<1] = 0.1 # replace
np.savetxt('converted.txt', a) # save to file
You could use regular expressions for parsing the string. I'm assuming here that the mantissa is never larger than 1 (ie, begins with 0). This means that for the number to be less than 1, the exponent must be either 0 or negative. The following regular expression matches '0', '.', unlimited number of decimal digits (at least 1), 'E' and either '+00' or '-' and two decimal digits.
0\.\d+E(-\d\d|\+00)
Assuming that you have the file read into variable 'text', you can use the regexp with the following python code:
result = re.sub(r"0\.\d*E(-\d\d|\+00)", "0.100000E+01", text)
Edit: Just realized that the description doesn't limit the valid range of input numbers to positive numbers. Negative numbers can be matched with the following regexp:
-0\.\d+E[-+]\d\d
This can be alternated with the first one using the (pattern1|pattern2) syntax which results in the following Python code:
result = re.sub(r"(0\.\d+E(-\d\d|\+00)|-0\.\d+E[-+]\d\d)", "0.100000E+00", subject)
Also if there's a chance that the exponent goes past 99, the regexp can be further modified by adding a '+' sign after the '\d\d' patterns. This allows matching digits ending in two OR MORE digits.
I've got the script working as I want now...thanks people.
When writing the list to a new file I used the replace method to get rid of the brackets and commas - is there a simpler way?
ftext = open("C:\\Users\\hhp06\\Desktop\\out.grd", "r")
otext = open("C:\\Users\\hhp06\\Desktop\\out2.grd", "w+")
for line in ftext:
stringnum = line.split()
floatnum = map(float, stringnum)
procnum = [(1.0 if num<1 else num) for num in floatnum]
stringproc = str(procnum)
s = (stringproc).replace(",", " ").replace("[", " ").replace("]", "")
otext.writelines(s + "\n")
otext.close()