反序列化序列化 table 或矩形化文本行列表

Deserializing a serialized table or rectangularifying a list of text lines

有时我的文本 table 不在列旁边的正常格式列中,而是在 列之后,即 table 的所有列在单独的文本行上一个接一个地列出。 (例如,当您从 PDF table 复制粘贴 table 时会发生这种情况。)

举个例子。正确的 table 看起来像这样:

Date        |  From - To              |  Flight   |  Departs Arrives        
------------|-------------------------|-----------|-------------------------
29-Jun-17   |  Sydney - Beijing       |  EK174    |  19:40 05:30 (30-Jun-17)
05-Jul-17   |  Beijing - Frankfurt    |  EK931    |  14:00 18:15            
12-Aug-17   |  Frankfurt - Shanghai   |  EK736    |  20:00 13:05 (13-Aug-17)
13-Aug-17   |  Shanghai - Sydney      |  EK175    |  19:35 08:10 (14-Aug-17)

但是我有以下几行的数据:

Date
29-Jun-17 
05-Jul-17 
12-Aug-17 
13-Aug-17
From - To
Sydney - Beijing 
Beijing - Frankfurt 
Frankfurt - Shanghai 
Shanghai - Sydney
Flight 
EK174 
EK931 
EK736 
EK175
Departs Arrives
19:40 05:30 (30-Jun-17)
14:00 18:15 
20:00 13:05 (13-Aug-17)
19:35 08:10 (14-Aug-17)

我的问题:是否有命令行工具可以将此列列表转换为前面提到的 table 它显然很像?(基于 unix 或其他)工具显然需要一些帮助来将列表分成列,例如,一个参数每列有多少行或类似的东西。

此外,这在我看来是一个转换问题。这是否在某些特定术语下已知(以便通过 Internet 搜索该术语更容易找到工具)? - 我称之为 ad hoc 类似于“矩形化列表”或“反序列化序列化 table"...

我建议 awk(gawk) + pr 方法:
首先,我们将输入文件分成 5 个单独的文件(每个文件用于一个单独的模式):

awk '/Date|From - To|Flight|Departs Arrives/{gsub(/^ +| +$/, "", [=10=]);fn=gensub(/[ -]+/, "-","g",[=10=]); 
print [=10=] > "/tmp/"fn; next}{print > "/tmp/"fn;}' testfile

上面的命令会在每个指定模式 /Date|From - To|Flight|Departs Arrives/

每次出现时将输入文件 testfile 拆分为多个文件

[=18=] - 指向 header(包含列名)行(例如 Date

gsub(/^ +| +$/, "", [=20=]); - 将从每个 header 行中去除所有尾随空格(例如 "Flight  ")

fn=gensub(/[ -]+/, "-","g",[=21=]); - 用单个破折号替换多个 spaces/dashes 以获得更合适的文件名。 fn 变量被分配了一个文件名

print [=23=] > "/tmp/"fn; - 将 header/pattern 行打印到相应的文件中(例如 Date 行将写入 /tmp/Date文件)

print > "/tmp/"fn; - 将所有后续记录写入相应文件,直到下一个模式出现。

最终,我们将获得以下文件: /tmp/Date/tmp/From-To/tmp/Flight/tmp/Departs-Arrives


现在,我们可以使用 pr 命令合并和格式化我们的文件以按列打印它们:

pr -t -m -w 100 -s"|" /tmp/Date /tmp/From-To /tmp/Flight /tmp/Departs-Arrives

输出:

Date            |From - To               |Flight          |Departs Arrives
29-Jun-17       |Sydney - Beijing        |EK174           |19:40 05:30 (30-Jun-17)
05-Jul-17       |Beijing - Frankfurt     |EK931           |14:00 18:15
12-Aug-17       |Frankfurt - Shanghai    |EK736           |20:00 13:05 (13-Aug-17)
13-Aug-17       |Shanghai - Sydney       |EK175           |19:35 08:10 (14-Aug-17)

要了解更多关于 pr 命令的信息:http://www.tutorialspoint.com/unix_commands/pr.htm

看到显然没有通过预先实施的文本转换的标准解决方案存在,这里是 Python 中的一个版本。输入在文件 series.txt 中给出,输出写入 table.txt,本例中每列的行数硬编码为 row_num = 5:

import csv

with open('series.txt', 'r') as inpfile:
    lines = inpfile.read().splitlines()
row_num = 5
# distribute to columns
cols = []
idx = 0
for l in lines:
    if idx == 0:
        cols.append([])
        idx = row_num

    cols[-1].append(l)
    idx -= 1;
# output columns
with open('table.txt', 'w') as csvfile:
    csvwriter = csv.writer(csvfile)
    for idx in range(0,row_num):
        out = ['{:<25}'.format(col[idx]) for col in cols]
        csvwriter.writerow(out)