反序列化序列化 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)
有时我的文本 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)