用于猜测当前表示为字符串的数据类型的方法

时间:2010-06-23 01:31:44

标签: python parsing csv input types

我目前正在解析CSV表,需要发现列的“数据类型”。我不知道值的确切格式。显然,CSV解析器输出的所有内容都是字符串。我目前感兴趣的数据类型是:

  1. 整数
  2. 浮点
  3. 日期
  4. 布尔
  5. string
  6. 我目前的想法是测试行的样本(可能是几百?),以确定通过模式匹配呈现的数据类型。

    我特别关注日期数据类型 - 是用于解析常见日期习语的python模块(显然我无法全部检测到它们)

    整数和浮点数怎么样?

5 个答案:

答案 0 :(得分:3)

解析日期时会想到

Dateutil

对于整数和浮点数,你总是可以在try / except部分

中尝试强制转换
>>> f = "2.5"
>>> i = "9"
>>> ci = int(i)
>>> ci
9
>>> cf = float(f)
>>> cf
2.5
>>> g = "dsa"
>>> cg = float(g)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for float(): dsa
>>> try:
...   cg = float(g)
... except:
...   print "g is not a float"
...
g is not a float
>>>

答案 1 :(得分:3)

ast.literal_eval()可以轻松获得。

答案 2 :(得分:2)

  

我目前感兴趣的数据类型是......

CSV文件中不存在这些内容。数据只是字符串。只要。没什么。

  

测试行样本

除了你在样本中看到的内容外,什么都不告诉你。样本后面的下一行可以是一个看起来与采样字符串完全不同的字符串。

处理CSV文件的唯一方法是编写假定特定数据类型并尝试转换的CSV处理应用程序。您无法“发现”很多关于CSV文件的信息。

如果列1应该是日期,则必须查看字符串并确定格式。它可能是任何东西。一个数字,一个美国或欧洲格式的典型格里高利日期(无法知道1/1/10是美国还是欧洲)。

try:
    x= datetime.datetime.strptime( row[0], some format )
except ValueError:
    # column is not valid.

如果第2列应该是浮点数,则只能执行此操作。

try:
    y= float( row[1] )
except ValueError:
    # column is not valid.

如果第3列应该是int,则只能执行此操作。

try:
    z= int( row[2] )
except ValueError:
    # column is not valid.

如果CSV具有浮点数字字符串,除非在每一行上执行float,否则无法“发现”。如果一行失败,则有人准备不正确的文件。

由于您必须进行转换以查看转换是否可行,因此您可以简单地处理该行。它更简单,一次性获得结果。

不要浪费时间分析数据。询问创建它的人是什么假设在那里。

答案 3 :(得分:2)

你可能对这个python库感兴趣,它对这种类型的猜测都是一般的python数据和CSV和XLS文件:

它很高兴扩展到非常大的文件,从互联网上传输数据等。

还有一个更简单的包装器库,其中包含一个名为dataconverters的命令行工具:http://okfnlabs.org/dataconverters/(和一个在线服务:https://github.com/okfn/dataproxy!)

进行类型猜测的核心算法是:https://github.com/okfn/messytables/blob/7e4f12abef257a4d70a8020e0d024df6fbb02976/messytables/types.py#L164

答案 4 :(得分:1)

我们测试了ast.literal_eval(),但是从错误中解救的速度非常慢,如果您要从以string收到的数据中进行投射,我认为正则表达式会更快。

以下内容对我们来说非常有效。

import datetime
import re

"""
Helper function to detect the appropriate type for a given string.
"""
def guess_type(s):
    if re.match("\A[0-9]+\.[0-9]+\Z", s):
        return float
    elif re.match("\A[0-9]+\Z", s):
        return int
    # 2019-01-01 or 01/01/2019 or 01/01/19
    elif re.match("\A[0-9]{4}-[0-9]{2}-[0-9]{2}\Z", s) or \
         re.match("\A[0-9]{2}/[0-9]{2}/([0-9]{2}|[0-9]{4})\Z", s): 
        return datetime.date
    elif re.match("\A(true|false)\Z", s):
        return bool
    else:
        return str

测试:

assert guess_type("this is a string") == str
assert guess_type("0.1") == float
assert guess_type("true") == bool
assert guess_type("1") == int
assert guess_type("2019-01-01") == datetime.date
assert guess_type("01/01/2019") == datetime.date
assert guess_type("01/01/19") == datetime.date