自动识别数据是否为表格文本格式

问题描述 投票:0回答:1

我的邮件是以下格式的文本:

  Name         Number1      Number2     Number3(ID)
somename1    1234.5678      273.4234      2783
somename2                   2384.2       12.54
somename3     234.1                     98234.2

可以看出,由于数据的性质,列中可能缺少一些数字。但是,Name列将始终包含某些内容,因为它是唯一标识符。

我正在以str形式获取此数据,并想弄清楚两件事:a)在数据中还给定其他字符串时,请弄清楚如何识别此列表格式数据(即,指示is_tabular = 1或否的指示符)。其他str数据将是其他一些非表格数据点。

b)如何自动保存此文本(为str格式)并以表格形式显示,尽管表中缺少数据点,也就是将其另存为Pandas DataFrame或NumPy数组或另一种有用的格式。问题是丢失的数据点与str的每一列之间的空格数并不总是一致。

我已经想到了各种方法来尝试保存此表格格式,以及识别给定的str是否为表格格式str。我考虑过预测方法,基于规则的方法(使用正则表达式),甚至OCR类型的方法,都可以将表格格式的字符串转换为Pandas DataFrame或其他方式。

但是,看来我的方法没有成功,我想知道是否有一种算法或方法可以用来将该字符串识别为表格(返回一个布尔值,说明该字符串是否为表格格式),以及是否有一种简便的方法将其转换为适当的数据格式,例如Pandas DataFrame,NumPy数组等,尽管缺少值。由于数据不是逗号分隔的(这只是某种格式的字符串,每行之间都有\n字符),所以我想知道这些列是否被空格分隔(如上所示) ,但是每行上的空格宽度可能不一致,是否有一种简便的方法可以将此文本转换为DataFrame?

python python-3.x pandas dataframe tabular
1个回答
0
投票

这样的启发式方法似乎行得通。它读取第一行以找出每个标头的起始偏移量,然后针对每一行使用该信息来找出每个数据最可能的列。

col_offset参数是当列标题不左对齐时所需的错误软键。数据的开始。可以通过不仅查看列,而且查看适当的行来替换它,以查看要调整多少以推断出的列起始偏移量以适应此情况。

import re

# at least 3 consecutive non-whitespace is data; adjust if necessary
data_re = re.compile(r"[\S]{3,}")


def examine_headers(header_row):
    column_headers = []
    for i, match in enumerate(data_re.finditer(header_row)):
        start = match.start(0)
        if i == 0:
            start = 0
        column_headers.append((match.group(0), start))
    return column_headers


def extract_row(column_headers, row, col_offset=0):
    row_data = {}
    for data_match in data_re.finditer(row):
        try:
            matching_header = [
                header
                for header in column_headers
                if header[1] <= (data_match.start(0) + col_offset)
            ][-1]
        except IndexError:
            print(f"No matching header for datum {data_match} on row {row}")
        else:
            row_data[matching_header[0]] = data_match.group(0)
    return row_data


# ------


rows = """
  Name         Number1      Number2     Number3(ID)
somename1    1234.5678      273.4234      2783
somename2                   2384.2       12.54
somename3     234.1                     98234.2
"""

rows = rows.strip("\n").splitlines()


column_headers = examine_headers(rows[0])

for row in rows[1:]:
    print(extract_row(column_headers, row, col_offset=2))

输出为

{'Name': 'somename1', 'Number1': '1234.5678', 'Number2': '273.4234', 'Number3(ID)': '2783'}
{'Name': 'somename2', 'Number2': '2384.2', 'Number3(ID)': '12.54'}
{'Name': 'somename3', 'Number1': '234.1', 'Number3(ID)': '98234.2'}
© www.soinside.com 2019 - 2024. All rights reserved.