Convert a number enclosed in parentheses (string) to a negative integer (or float) using Python?
Question:
In Python, what is the simplest way to convert a number enclosed in parentheses (string) to a negative integer (or float)?
For example, ‘(4,301)’ to -4301, as commonly encountered in accounting applications.
Answers:
The simplest way is:
my_str = "(4,301)"
num = -int(my_str.translate(None,"(),"))
Since you are reading from a system that put in thousands separators, it’s worth mentioning that we are not using them the same way all around the world, which is why you should consider using a locale system. Consider:
import locale
locale.setlocale( locale.LC_ALL, 'en_US.UTF-8' )
my_str = "(4,301)"
result = -locale.atoi(my_str.translate(None,"()"))
Assuming just removing the ,
is safe enough, and you may wish to apply the same function to values that may contain negative numbers or not, then:
import re
print float(re.sub(r'^((.*?))$', r'-1', a).replace(',',''))
You could then couple that with using locale
as other answers have shown, eg:
import locale, re
locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8')
print locale.atof(re.sub('^((.*?))$', r'-1', a))
This code could be a little bit longer, but straight forward and easy to maintain
from pyparsing import Word, nums, OneOrMore
integer = Word(nums)
text = "blah blah (4,301) blah blah "
parser = OneOrMore(integer)
iterator = parser.scanString( text )
try:
while True:
part1 = iterator.next()
part2 = iterator.next()
except:
x = part1[0][0][0] + '.' +part2[0][0][0]
print -float(x)
Produces: -4.301
Presumably you want to handle positive numbers as well as negative, which is missing from many of the answers thus far. I’m going to add a bit to the answer from mogul.
import locale
locale.setlocale( locale.LC_ALL, '')
my_str = '( 4,301 )'
positive = my_str.translate(None, '()')
result = locale.atoi(positive) if positive == my_str else -locale.atoi(positive)
For Python 3.6, and also handles ‘-‘ as 0, and strips excess empty spaces:
def clean_num(num_string):
bad_chars = '(),-'
translator = str.maketrans('', '', bad_chars)
clean_digits = num_string.translate(translator).strip()
if clean_digits == '':
return 0
elif '(' in num_string:
return -float(clean_digits)
else:
return float(clean_digits)
For localized numbers, I use this:
def clean_number(text):
import locale
locale.setlocale(locale.LC_NUMERIC, "Portuguese_Brazil.1252")
tbl = str.maketrans('(', '-', 'R$ )')
return locale.atof(text.translate(tbl))
Works with Python 3.8.
The first parenthesis is replaced with the minus sign, the second is removed.
Also removes spaces and the monetary sign.
As of today, the top answer is specific to Python 2. I tried editing it, but the queue is full.
For my_str = "(4,301)"
, the top answer advises:
num = -int(my_str.translate(None,"(),"))
For Python 3, you would instead use one of the following:
translate_table = dict({ord(i): None for i in '(),'})
num = -int(my_str.translate(translate_table))
or, more simply
num = -int(my_str.translate({ord(i): None for i in "(),"}))
If you’re curious, the change is necessary for two reasons:
-
str.translate()
now expects a single argument.
-
The str
type contains Unicode. This is why each key in the dictionary is first passed to ord
: this function accepts a given Unicode character and returns the Unicode code point for it:
>>> ord('(')
40
In Python, what is the simplest way to convert a number enclosed in parentheses (string) to a negative integer (or float)?
For example, ‘(4,301)’ to -4301, as commonly encountered in accounting applications.
The simplest way is:
my_str = "(4,301)"
num = -int(my_str.translate(None,"(),"))
Since you are reading from a system that put in thousands separators, it’s worth mentioning that we are not using them the same way all around the world, which is why you should consider using a locale system. Consider:
import locale
locale.setlocale( locale.LC_ALL, 'en_US.UTF-8' )
my_str = "(4,301)"
result = -locale.atoi(my_str.translate(None,"()"))
Assuming just removing the ,
is safe enough, and you may wish to apply the same function to values that may contain negative numbers or not, then:
import re
print float(re.sub(r'^((.*?))$', r'-1', a).replace(',',''))
You could then couple that with using locale
as other answers have shown, eg:
import locale, re
locale.setlocale(locale.LC_ALL, 'en_GB.UTF-8')
print locale.atof(re.sub('^((.*?))$', r'-1', a))
This code could be a little bit longer, but straight forward and easy to maintain
from pyparsing import Word, nums, OneOrMore
integer = Word(nums)
text = "blah blah (4,301) blah blah "
parser = OneOrMore(integer)
iterator = parser.scanString( text )
try:
while True:
part1 = iterator.next()
part2 = iterator.next()
except:
x = part1[0][0][0] + '.' +part2[0][0][0]
print -float(x)
Produces: -4.301
Presumably you want to handle positive numbers as well as negative, which is missing from many of the answers thus far. I’m going to add a bit to the answer from mogul.
import locale
locale.setlocale( locale.LC_ALL, '')
my_str = '( 4,301 )'
positive = my_str.translate(None, '()')
result = locale.atoi(positive) if positive == my_str else -locale.atoi(positive)
For Python 3.6, and also handles ‘-‘ as 0, and strips excess empty spaces:
def clean_num(num_string):
bad_chars = '(),-'
translator = str.maketrans('', '', bad_chars)
clean_digits = num_string.translate(translator).strip()
if clean_digits == '':
return 0
elif '(' in num_string:
return -float(clean_digits)
else:
return float(clean_digits)
For localized numbers, I use this:
def clean_number(text):
import locale
locale.setlocale(locale.LC_NUMERIC, "Portuguese_Brazil.1252")
tbl = str.maketrans('(', '-', 'R$ )')
return locale.atof(text.translate(tbl))
Works with Python 3.8.
The first parenthesis is replaced with the minus sign, the second is removed.
Also removes spaces and the monetary sign.
As of today, the top answer is specific to Python 2. I tried editing it, but the queue is full.
For my_str = "(4,301)"
, the top answer advises:
num = -int(my_str.translate(None,"(),"))
For Python 3, you would instead use one of the following:
translate_table = dict({ord(i): None for i in '(),'})
num = -int(my_str.translate(translate_table))
or, more simply
num = -int(my_str.translate({ord(i): None for i in "(),"}))
If you’re curious, the change is necessary for two reasons:
-
str.translate()
now expects a single argument. -
The
str
type contains Unicode. This is why each key in the dictionary is first passed toord
: this function accepts a given Unicode character and returns the Unicode code point for it:>>> ord('(') 40