如何始终如一地转换字符串,如;3.71B“;及;4M“;用Python编写数字?

如何始终如一地转换字符串,如;3.71B“;及;4M“;用Python编写数字?,python,regex,finance,yahoo-finance,Python,Regex,Finance,Yahoo Finance,我有一些相当混乱的代码,几乎可以从雅虎金融为公司提供的有形价格/书籍(一个名为ystockquote的不错的模块已经获得了无形价格/书籍的价值) 我的问题是: 对于计算中的一个变量,流通股我得到的字符串类似于10.89B和49m,其中B和m分别代表十亿和百万。我在将它们转换为数字时遇到困难,我现在的位置是: shares=''.join(node.findAll(text=True)).strip().replace('M','000000').replace('B','000000000').

我有一些相当混乱的代码,几乎可以从雅虎金融为公司提供的有形价格/书籍(一个名为
ystockquote
的不错的模块已经获得了无形价格/书籍的价值)

我的问题是:

对于计算中的一个变量,流通股我得到的字符串类似于10.89B49m,其中Bm分别代表十亿和百万。我在将它们转换为数字时遇到困难,我现在的位置是:

shares=''.join(node.findAll(text=True)).strip().replace('M','000000').replace('B','000000000').replace('.','') for node in soup2.findAll('td')[110:112]
这是相当混乱的,但我认为如果

.replace('M','000000').replace('B','000000000').replace('.','') 
我使用了一个带有变量的正则表达式。我想问题只是哪个正则表达式和变量。其他建议也很好

编辑:
具体地说,我希望能有一些适用于0、1或2位小数的数字,但这些答案看起来都很有用。

将数字解析为浮点数,并使用乘数映射:

multipliers = dict(M=10**6, B=10**9)
def sharesNumber(nodeText):
    nodeText = nodeText.strip()
    mult = 1
    if nodeText[-1] in multipliers:
        mult = multipliers[nodeText[-1]]
        nodeText = nodeText[:-1]
    return float(nodeText) * mult
如果需要,也可以
int()
结果

num_replace = {
    'B' : 1000000000,
    'M' : 1000000,
}

a = "4.9M" 
b = "10.89B" 

def pure_number(s):
    mult = 1.0
    while s[-1] in num_replace:
        mult *= num_replace[s[-1]]
        s = s[:-1]
    return float(s) * mult 

pure_number(a) # 4900000.0
pure_number(b) # 10890000000.0
这将与白痴一起工作,比如:

pure_number("5.2MB") # 5200000000000000.0
由于采用了字典方法,您可以以一种易于维护的方式添加任意多的后缀,并且您可以通过以一种大写形式表示dict键,然后执行
.lower()
.upper()
使其匹配,从而使其更加宽松

num_replace = {
    'B' : 'e9',
    'M' : 'e6',
}

def str_to_num(s):
    if s[-1] in num_replace:
        s = s[:-1]+num_replace[s[-1]]
    return int(float(s))


所以
'3.71B'
->
'3.71e9'
->
3700000000L
等等。

这可能是一个安全使用eval的机会!!:-)

考虑以下片段:

>>> d = { "B" :' * 1e9', "M" : '* 1e6'}
>>> s = "1.493B"
>>> ll = [d.get(c, c) for c in s]
>>> eval(''.join(ll), {}, {})
1493000000.0
现在,将所有内容组合成一行:

d = { "B" :' * 1e9', "M" : '* 1e6'}

def human_to_int(s):
    return eval(''.join([d.get(c, c) for c in s]), {}, {})

print human_to_int('1.439B')
print human_to_int('1.23456789M')
回馈:

1439000000.0
1234567.89

我认为这两种方法中的任何一种都能奏效,但最下面的一种似乎更容易,所以我先试试。
>sharesNumber('4.1234567889b')4123456788.999995
>sharesNumber('123456789.987654321B')1.2345678998765434e+17
@jamylak:我怀疑股数会不会那么大。
>4123456788.999999 5
>>纯_数('1234567889.987654321B')1.2345678998765434e+17
@jamylak这是一种表示不准确。即使是python int或long也有精度限制,只需多给几个数字。解决方案
>>text_to_num('4.123456781234B')#4123456789L
没有问题。茨克茨克。精度:)我假设他只有整数输入,所以这不是问题,这个解决方案仍然正确,直到有人传递一个次十进制的解析输入,它才是“正确的”。也许你应该抛出一个异常来强化这个假设。哈哈,代码大战!你们太棒了,他们不仅是整数,而且你们的任何一个解决方案都足够了,因为它不需要那么具体。不过,每种情况下只有两个小数,所以就我所见,@jamylak实际上赢得了这场代码大战。不幸的是,我得到了你们两位解决方案的
inf
,但我认为这是我的错,因为@jamylak已经证明了每个人的代码都可以正常工作;)我选择他的答案,一部分是因为他的热情,一部分是因为我的评论(最多两位小数),尽管int假设是不正确的。谢谢与您的问题无关,请注意
join.strip.replace.replace.replace
构造,它们很难阅读,也很难调试。看到并完全遵守它们。你未来的自我会感谢你。与不相关的无关:我特别喜欢
导入这部
另请参见
导入反重力
我喜欢那部漫画。Python是我的sizzurp。
ast.literal\u eval
更安全,不需要作为
eval
namespace@jamylak
ast.literal\u eval
仅适用于文字,而不适用于表达式-因此不能在上述代码中替换:哦,对不起,我错过了字符串中的
“*”
。我今天看不清楚。注意,如果删除
“*”
,则
ast.literal\u eval
将起作用,尽管在这种情况下,您只需使用
int
,并且更加明确,并且该解决方案已经发布。True。。但是我的解决方案是完全功能的,而int解决方案需要
if
语句:-)Ah ok then+1 then,尽管您应该删除
'*1'
并使用
ast.literal\u eval
d = { "B" :' * 1e9', "M" : '* 1e6'}

def human_to_int(s):
    return eval(''.join([d.get(c, c) for c in s]), {}, {})

print human_to_int('1.439B')
print human_to_int('1.23456789M')
1439000000.0
1234567.89