我收到了一份表格数据的PDF文件,我已将其转换为纯文本进行处理.
pdftotext -nopgbrk -layout file.pdf
Run Code Online (Sandbox Code Playgroud)
这做了相当不错的工作,但是使用空格来分隔/分隔列中的字段,并且似乎主要对保留视觉布局而不是"结构"布局感兴趣,即没有一致或可靠的分隔符.所以现在我将2个或更多空格转换为标签:
sed -i 's/[[:space:]]\{2,\}/\t/g' file.txt
Run Code Online (Sandbox Code Playgroud)
使用cat -vte我看到这在文件中放置标签确实很不错....但是,第二个字段存在一些不一致之处,我想请你帮忙.
请参阅以下比较以获得澄清:
正常/预期结果:
79879 5.6 0.5 MG EN SQ TFK World Report 09-24-2004 Time for Kids Editors, ORD1915643 79880 5.5 0.5 MG EN SQ TFK World Report 10-01-2004 Time for Kids Editors, ORD1915643 79881 6.0 0.5 MG EN SQ TFK World Report 10-08-2004 Time for Kids Editors, ORD1915643 79882 5.5 0.5 MG EN SQ TFK World Report 10-22-2004 Time for Kids Editors, ORD1915643 79883 5.9 0.5 MG EN SQ TFK World Report 10-29-2004 Time for Kids Editors, ORD1915643
一些奇怪和不一致:
72 5.2 3.0 MG EN LS Ramona and Her Father Cleary, Beverly ORD2111460 491 4.8 4.0 MG EN LS Ramona and Her Mother Cleary, Beverly ORD1748201 134 5.6 3.0 MG EN LS Ramona Quimby, Age 8 Cleary, Beverly ORD1748201 29 4.7 5.0 MG EN LS From the Mixed-Up Files of Mrs. Basil E. Konigsburg, E.L. ORD1525579
请注意,"smushing"效果可能出现在字段2或字段3 ... AND中,字段数与"正常"结果相差1或2.
...所以,为了解决这个问题,我尝试了以下内容:
awk -F'\t' 'OFS="\t";$1 ~ /^[[:digit:]]/{print $1,gensub(/[[:space:]]/,"\t","g",$2),$3,$4,$5,$6,$7}' file.txt
Run Code Online (Sandbox Code Playgroud)
这似乎使每个或至少大多数行加倍并切断字段.
编辑 这似乎工作......到目前为止,还在测试.
awk -F'\t' '{$2 = gensub( /[[:space:]]/, "\t", "g", $2 );
$3 = gensub( /[[:space:]]/, "\t", "g", $3 )}
{OFS="\t";print}' file.txt
Run Code Online (Sandbox Code Playgroud)
有没有一种简单的方法来使用awk解决这个问题?
UPDATE
有些人要求在我的空间标签转换之前代表状态的样本.以下表示前一个样本在文档中的位置附近的示例.看起来一样......除了一个[下面]间隔,另一个[上面]标签.请注意pdftotext在下面的不同示例中处理第2列的方式...有时会拆分,有时会生成单个列.
样本1:
72 5.2 3.0 MG EN RP Ramona and Her Father Cleary, Beverly ORD0630871
are orphans
491 4.8 4.0 MG EN RP Ramona and Her Mother Cleary, Beverly ORD0785414
are also orphans
186 4.8 4.0 MG EN RP Ramona Forever Cleary, Beverly ORD0630871
forever the orphan
样本2:
79871 5.7 0.5 MG EN SQ TFK World Report 03-18-2005 Time for Kids Editors, ORD1915643 79872 5.8 0.5 MG EN SQ TFK World Report 04-01-2005 Time for Kids Editors, ORD1915643 79873 6.0 0.5 MG EN SQ TFK World Report 04-08-2005 Time for Kids Editors, ORD1915643
更新2
对Ed的提交进行了以下更改.认为它可以简化,但它的工作原理.它必须允许孤立的线.
$1 ~ /^[[:digit:]]+/{
for (i=1;i<=6;i++)
printf "%s\t", $i
n = split($0,tmp,/ +/)
for (i=2;i>=0;i--)
printf "%s\t", tmp[n-i]
print ""
}
$1 ~ /^[^[:digit:]]+/ {print $0}
Run Code Online (Sandbox Code Playgroud)
也许这更漂亮:
{
if ($1 ~ /^[[:digit:]]+/) {
for (i=1;i<=6;i++)
printf "%s\t", $i
n = split($0,tmp,/ +/)
for (i=2;i>=0;i--)
printf "%s\t", tmp[n-i]
print ""
}
else print $0;
}
Run Code Online (Sandbox Code Playgroud)
您的原始awk脚本似乎是每行加倍因为OFS="\t"计算结果true,因此打印当前行.把它放在一个BEGIN{}块中以避免重复:
gawk -F'\t' 'BEGIN{OFS=FS} $1 ~ /^[[:digit:]]/ {print $1,gensub(/[[:space:]]/,"\t","g",$2),$3,$4,$5,$6,$7}' file.txt
Run Code Online (Sandbox Code Playgroud)
请注意,它gensub()是一部分gawk,因此不可移植.你可以用这个来实现同样的东西:
awk -F'\t' 'BEGIN{OFS=FS} $1 ~ /^[[:digit:]]/ {gsub(/[[:space:]]/,"\t",$2); print $1,$2,$3,$4,$5,$6,$7}' file.txt
Run Code Online (Sandbox Code Playgroud)
那说...随着你的更新,我可以看到原始数据格式足够好,我们可以按原样处理它.令人烦恼的是你在第2列和第4列之间只有一个空格,或者我们可以简单地使用多个空格作为字段分隔符.但它仍然是一种可预测的输入格式.
看来,对于前6个字段,输入由"任何空格"分隔,对于最后3个字段,它由"两个或更多个空格"分隔.考虑到这一点,我们可以使用以下awk来解析您的输入数据:
#!/usr/bin/awk -f
BEGIN {
FS=" +";
fmt="----\n1=%s\n2=%s\n3=%s\n4=%s\n5=%s\n6=%s\n7=%s\n8=%s\n9=%s\n";
}
{
# Grab the right-hand fields, separated by FS
a[7]=$(NF-2); a[8]=$(NF-1); a[9]=$NF;
# Then trim the line and grab initial fields, separated by whitespace
sub(/^ +/, "");
split($0, easy, /[[:space:]]+/);
for(i=1;i<=6;i++) {
a[i]=easy[i+1];
}
printf(fmt, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9]);
}
Run Code Online (Sandbox Code Playgroud)
这假设您的第二个最后一个字段和最后一个字段之间的间隔总是会有超过1个空格(如您在问题中提供的输入数据中所示).如果这不是一个安全的假设,你/我们可以编码.
根据需要调整输出.