将PDF或FDF转换为CSV?

听起来有点疯狂,但是虽然Libre Base可以将表单导出为PDF,但无法将已完成的表单数据从PDF导入到Libre Base。

一个想法是将PDF表单数据提取为FDF(或不友好的CSV),然后将其转换为友好的CSV,这样就可以将CSV数据复制粘贴到Libre Base中。

  • 如何使用以下方式将PDF、FDF或不友好的CSV文件转换为友好的CSV:
    • 第一行:“FieldName1, FieldName2, ...”
    • 第二行:“Value1, Value2, ...”

2015年2月25日之前在Ge.tt上有用的文件

  1. 超基本的空白PDF,"提交格式"为FDF
    • Libre Base > 表单 > 编辑 > 打开数据库对象 --> 文件 > 导出为PDF
  2. 由(1)生成的填充PDF
    • 手动输入数据
  3. 从(2)提取的CSV数据
    • pdftk filled_form-submit_format_fdf.pdf dump_data_fields output filled_form.csv
  4. 从(2)提取的FDF数据
    • pdftk filled_form-submit_format_fdf.pdf generate_fdf output filled_form.fdf
*注意:您也可以使用Libre Base将空白表单导出为XML或HTML,但我不知道如何在这些文件中输入数据,也不知道如何将数据导入回Base。

1请问您能提供一个样本PDF文件吗? - αғsнιη
2因为PDF被视为一种终端、仅用于存档的格式,就像打印一样。有成千上万种方法可以伪造一个外观完全相同的PDF文件,解析所有这些方式将非常复杂。Libre Base不能保存/导出其他格式吗?否则,您可以尝试使用pdftotext和一些(或很多)脚本来处理。 - Rmano
FDF是一个很好的起点,因为它是基于文本的,并且具有清晰的字段名/值结构的表单数据。例如,使用Perl将其转换为CSV应该不太困难,但这与Ubuntu无关,所以这个话题不在讨论范围内。 - tohuwawohu
@Rmano:我希望Base能够解码Base创建的PDF文件。Base可以将表单导出为PDF、HTML或XML,但我不知道如何要求他人在HTML或XML文件中输入数据。那个脚本对我来说太难了。谢谢。 - jtd
@tohuwawohu: 我不懂 Perl。那个脚本对我来说太难了。谢谢。 - jtd
@jtd 你本可以直接撤销我的编辑。那次编辑的目的是为了让人们不必去那里逐个下载文件。 - muru
1@muru:抱歉。我以为AU会自动更改链接,而且由于那些API链接对我来说失败了,所以我进行了更改。不过,我想我找到了一个能满足你关注的解决方案。 - jtd
@jtd 好的。我在你的 filled_form.csv 文件中看到了其他字段,比如 FieldTypeFieldFlagsFieldJustification;你是如何从 PDF 文件中获取它们的?它们是固定值吗?最后一个问题:filled_form.csv 是你想要的最终结果吗?请编辑问题,并添加更多细节,包括你的输入文件(哪个文件?)和你期望的结果(从输入文件中得到的输出)。谢谢 - αғsнιη
请注意,Libre Base在导出PDF时会创建一个(平面)PDF“文档”。但是,您想要导入到Base中的是“数据”。PDF使“数据”可用的方式是通过表单字段(在导出时没有)。 - Max Wyss
@KasiyA:问题现在展示了如何生成每个文件。我想将2、3或4个(相同数据,不同格式)的数据作为记录导入到Base中。按照问题描述中所述,使用一个新的CSV作为中间介质是可以的(第1行,第2行,...)。 - jtd
@MaxWyss:我使用了pdftk(感谢@tohuwawohu)来提取2中的表单字段数据,并生成了文件3和4。但是,我仍然无法将3和4中的表单字段数据作为记录导入到Base中。 - jtd
3个回答

如何将FDF转换为CSV?
选项A:
awk -F "[()]" '{ if ($1=="/V ") value[$2];} \
    END {printf( "CompanyName\tEmailAddress\t\tCountryOrRegion\n" ); \
           for (x in value)printf("%s\t", x);print "" ; \
    }' filled_form.fdf > filled_form.CSV

选项B:
grep -oP '(?<=\/T \(txt).*(?=\))' filled_form.fdf |awk '{ORS=(NR%3?",":RS)}1'; \
grep -oP '(?<=\/V \().*(?=\))' filled_form.fdf |awk '{ORS=(NR%3?",":RS)}1'; 

上述命令的简化版本如下:
paste -sd, <(grep -oP '(?<=\/T \(txt).*(?=\))' filled_form.fdf) <(grep -oP '(?<=\/V \().*(?=\))' filled_form.fdf)

选项C:
awk 'NR%2==0{type[$0]} NR%2{value[$0]} END{for (x in type)printf("%s\t", x);print "" ;for (y in value)printf("%s\t", y);print "" ;}' <(grep -oP '(?<=\/T \(txt|\/V \().*(?=\))' filled_form.fdf)

如何将不友好的CSV文件转换为友好的CSV文件?
选项A:
awk -F: '{ if ($1=="FieldValue") value[$2];} \
    END {printf( "CountryOrRegion\tCompanyName\tEmailAddress\n" ); \
           for (x in value)printf("%s\t", x) ;print ""; \
    }' filled_form.csv > friendly_filled_form.CSV

选项B:
grep -oP '(?<=FieldName: txt).*' filled_form.csv |awk '{ORS=(NR%3?",":RS)}1'; \
grep -oP '(?<=FieldValue: ).*' filled_form.csv |awk '{ORS=(NR%3?",":RS)}1'

*请注意,此命令是一行的。因此,在运行时您需要输入/复制两行。

这个命令的简短版本如下:

paste -sd, <(grep -oP '(?<=FieldName: txt).*' filled_form.csv) <(grep -oP '(?<=FieldValue: ).*' filled_form.csv)

选项C:
awk 'NR%2{type[$0]} NR%2==0{value[$0]} END{for (x in type)printf("%s\t", x);print "" ;for (y in value)printf("%s\t", y);print "" ;}' <(grep -oP '(?<=FieldName: txt|FieldValue: ).*' filled_form.csv)

或者甚至这个:
awk 'NR%2{type[$0]} NR%2==0{value[$0]} END{for (x in type)printf("%s\t", x);print "" ;for (y in value)printf("%s\t", y);print "" ;}' <(awk -F'FieldValue: |FieldName: txt' 'NF>1{print $2}' filled_form.csv)

如何将PDF转换为CSV?
明天我会用pdfgrep完成解决方案,但如果你想自己尝试,这是命令:
pdfgrep 'CompanyName|CountryOrRegion|EmailAddress' filled_form-submit_format_fdf.pdf

它需要在输出格式上进行调整。如果你只想得到完整的单词,请使用-C 0选项。祝你好运,希望能帮到你 ;)

1这太聪明了。我将使用单选按钮、复选框等进行尝试,并查看pdfgrep或其他选项是否能处理。谢谢! - jtd

回答你在这里的评论:
我希望Base能解码Base创建的PDF文件。
不,期望任何程序能够读取它生成的PDF文件是不合理的,就像期望打印机能够将刚刚打印的纸张返回并还给你一样,这是不可能的。
PDF是一种打印/存档格式。它基本上是一系列指令,例如“将单词hello放在页面的位置x,y”。所以当你在PDF中看到:

example PDF

计算机程序无法确定它是2行3列还是2行2列包含空格(2)。数字3可能是2.95四舍五入后的结果。你无法知道,因为信息根本不存在。所以,不,你永远不会认为从PDF返回到你的数据应该是可能的(3)。

然而,你可以尝试将信息转换为更易于处理的形式,例如使用pdftotext(4):

[romano:~/tmp] 1 % pdftotext Untitled1.pdf; cat Untitled1.txt
Sheet1

shiny
mint

new
used

3
1

Page 1

...然后使用脚本、手动编辑或其他方式来进行修饰。

脚注:

(1) 这里真的是非常、非常的轻描淡写。

(2) 真的是2乘2的,毫不夸张。

(3) 我甚至见过一些PDF文件,创建程序为了几乎不可能篡改它,将每个字形独立且随机地放置在页面上。不,我找不到那个例子了……

(4) 来自poppler-utils软件包。


谢谢你的回答。虽然我对PDF编码一无所知,但Base似乎生成了一个不仅包含打印信息的pdf文件。它还包含表单字段信息,例如FieldName1= "CompanyName",Value1= ""(任何人都可以更改后者的值)。其他程序(如pdftk)可以读取这些值(请参阅我在Ge.tt上的文件)。这就是为什么我希望并错误地假设Base能够读取表单字段信息并导入的原因。 - jtd

LibreOffice可以生成PDF表单。
使用免费的Foxit Reader可以将数据转换为CSV格式,该软件在Bionic Beaver 18.04下运行良好。
在Foxit Reader中加载完成的表单后,从“连接”下拉菜单中选择“表单”。然后,工具栏上会出现一个按钮,提供“导出表单数据”的选项。保存窗口将提供XML、XFDF(不知道是什么)、TXT和CSV等选择。