如何在Python中将Unicode字符转换为浮点数?

14

我正在解析一个包含分数Unicode表示的网页。 我希望能够直接将这些字符串转换为浮点数。 例如:

"⅕" 将变成 0.2

有什么建议可以在Python中完成这个任务吗?

7个回答

33

您想使用unicodedata模块:

import unicodedata
unicodedata.numeric(u'⅕')

这将打印:

0.20000000000000001
如果字符没有数值,那么unicodedata.numeric(unichr[, default])将返回默认值,如果未提供默认值,则会引发ValueError异常。

6
Python应该向苹果借用口号:“有一个模块可以解决这个问题”。 - John Fouhy
直到我刚才阅读文档才意识到ftp.unicode.org有一个UnicodeData.txt文件,这就是unicodedata模块获取所有数据的位置。 - Karl Voigtland
我从来不知道你可以这样做! - mhawke
我也没有 - 真的很惊人 - Martin Beckett
3
对于那些好奇的人来说,Python实现的数值模块基本上就是一个大查找表,可以参见python/trunk/Objects/unicodectype.c。此外,显然有很多Unicode字符具有数值价值,不仅限于标准分数...例如,请查看http://www.fileformat.info/info/unicode/char/0f2e/index.htm! - akent

6
那些浮点数的Unicode表示被称为分数符号
您可以使用unicodedata.numeric(char)将它们转换为浮点数。
然而,numeric(char)在处理这样的内容时无法正常工作。这需要更多的努力:
from unicodedata import numeric

samples = ["3¼","19¼","3 ¼","10"]

for i in samples:
    if len(i) == 1:
        v = numeric(i)
    elif i[-1].isdigit():
        # normal number, ending in [0-9]
        v = float(i)
    else:
        # Assume the last character is a vulgar fraction
        v = float(i[:-1]) + numeric(i[-1])
    print(i, v)

输出:

3¼ 3.25
19¼ 19.25
3 ¼ 3.25
10 10.0

你可能也会对使用正则表达式从更广泛的用户输入中隔离这些普通分数感兴趣。您可以使用它们的Unicode字符代码范围来实现此操作:
/[\u2150-\u215E\u00BC-\u00BE]/g

示例:https://regexr.com/3p8nd


1

由于Unicode中只定义了有限数量的分数,因此使用字典似乎是合适的:

Fractions = {
    u'¼': 0.25,
    u'½': 0.5,
    u'¾': 0.75,
    u'⅕': 0.2,
    # add any other fractions here
}

更新:使用unicodedata模块是更好的解决方案。


具体来说,您正在查看字符U+00BC-E(http://www.unicode.org/charts/PDF/U0080.pdf)和U+2153-E(http://www.unicode.org/charts/PDF/U2150.pdf)。只需在索引(http://www.unicode.org/Public/UNIDATA/Index.txt)中搜索“vulgar”即可。 - Ben Blank

1
也许你可以使用"unicodedata"模块来分解这个分数,然后查找FRACTION SLASH字符,接下来就是简单的除法问题了。
例如:
>>> import unicodedata
>>> unicodedata.lookup('VULGAR FRACTION ONE QUARTER')
u'\xbc'
>>> unicodedata.decomposition(unicodedata.lookup('VULGAR FRACTION ONE QUARTER'))
'<fraction> 0031 2044 0034'

更新:我会将这个答案保留在这里供参考,但是根据Karl的回答,使用unicodedata.numeric()是一个更好的选择。


0
我这里说的很明显,但是将其扩展到人们写下“1¾”表示“1.75”也非常简单,因此我在这里分享一下以供快速参考:
import unicodedata

# Assuming that the unicode is always the last character. You always going to see stuff like "3¼", or "19¼" whereas stuff like "3¼5"
# does not have a clear interpretation 

def convertVulgarFractions(vulgarFraction):

    if (len(vulgarFraction) == 1):
        return unicodedata.numeric(vulgarFraction)

    if (len(vulgarFraction) > 1) & (not (vulgarFraction[:len(vulgarFraction)-1].isdigit())):
        raise ArithmeticError("The format needs to be numbers ending with a vulgar fraction. The number inserted was " + 
                              str(vulgarFraction))

    if vulgarFraction[len(vulgarFraction)-1].isdigit():
        return float(vulgarFraction)
    else:
        return float(vulgarFraction[:len(vulgarFraction)-1]) + unicodedata.numeric(vulgarFraction[len(vulgarFraction)-1])

0

虽然不完全符合要求,但也许有人想将其转换为分数而不是浮点数。毕竟,它真正代表的是一个分数。

unicodedata.normalize("NFKC", "⅕") 的结果是 "1⁄5"。这目前还不能被 fractions.Fraction 理解,因为它期望用 / 而不是 描述分数。不过,这很容易替换:

In [313]: def unifrac_to_frac(s):
     ...:     return fractions.Fraction(unicodedata.normalize("NFKC", s).replace("⁄", "/"))
     ...: 

In [315]: unifrac_to_frac("⅕")
Out[315]: Fraction(1, 5)

In [316]: unifrac_to_frac("½")
Out[316]: Fraction(1, 2)

In [317]: unifrac_to_frac("↉")
Out[317]: Fraction(0, 1)

0
在Python 3.1中,您不需要使用'u',它将产生0.2而不是0.20000000000000001。
>>> unicodedata.numeric('⅕')
0.2

2
断言(assert)(0.2 == 0.20000000000000001)...你可能想要表达的是 unicodedata.numeric() 生成的浮点数没有改变,但 repr() 已经被增强以在可能的情况下生成一个不那么令人恐惧但仍然计算等效的答案。 - John Machin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接