`awk`-pandoc生成的纯文本表,包含空格的字段/单元格/值

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

我已经多次遇到这个问题,也许这只是我的简单技术,因为我仍然有点文本处理的新手点,但使用从pandochtmlplain会产生相当多的表格的:

 #   IP Address          Device Name             MAC Address
--- ------------- -------------------------- -------------------
 1   192.168.1.3   ANDROID-FFFFFFFFFFFFFFFF   FF:FF:FF:FF:FF:FF
 2   192.168.1.4           XXXXXXX            FF:FF:FF:FF:FF:FF
 3   192.168.1.5              --              FF:FF:FF:FF:FF:FF
 4   192.168.1.6              --              FF:FF:FF:FF:FF:FF
--- ------------- -------------------------- -------------------

此示例中的列标题(以及字段/单元格/其他内容中的任何内容)并不特别awk友好,因为它们包含空格。必须有一些实用程序(或pandoc选项)来添加分隔符或以简单的方式处理它,以便更容易与awk一起使用(因为破折号的裁定提示为最大列宽),但我快速接近我的知识极限,无法自己找到任何好的解决方案。我很感激任何帮助,我会接受替代方法(我只是使用pandoc,因为这就是我所知道的)。

bash shell awk pandoc
2个回答
2
投票

我有一个解决方案,它解析虚线以获得列长度,然后使用该信息将每行划分为列(类似于@shellter在评论中提出的,但不需要硬编码值)。

首先,在BEGIN块中,我们读取了标题行和破折号行。然后我们将通过拆分虚线并处理它来获取列长度。

BEGIN {
    getline headers
    getline dashline

    col_count = split(dashline, columns, " ")
    for (i=1;i<=col_count;i++)
        col_lens[i] = length(columns[i])
}

现在我们有每列的长度,你可以在主体内使用它。

{
    start = 1
    for (i=start;i<=col_count;i++){ 
        col_n = substr($0, start, col_lens[i])
        start = start + col_lens[i] + 1
        printf("column %i: [%s]\n",i,col_n);
    }
}

这似乎有点麻烦,但它确实有效。我相信这回答了你的问题。为了让事情变得更好,我将这条线解析为user defined function。这很方便,因为您现在可以在存储的标题上使用它(如果需要)。

这是完整的解决方案:

function parse_line(line, col_lens, col_count){
    start = 1
    for (i=start;i<=col_count;i++){
        col_i = substr(line, start, col_lens[i])
        start = start + col_lens[i] + 1
        printf("column %i: [%s]\n", i, col_i)
    }
}    
BEGIN { 
        getline headers
        getline dashline
        col_count = split(dashline, columns, " ")
        for (i=1;i<=col_count;i++){
            col_lens[i] = length(columns[i])
        }

        parse_line(headers, col_lens, col_count);
}
{
        parse_line($0, col_lens, col_count);
}

如果你把你的示例表放到一个名为table的文件中,并将这个程序放到一个名为dashes.awk的文件中,这里是输出(使用head -n -1删除最后一行破折号):

$ head -n -1 table | awk -f dashes.awk 
column 1: [ # ]
column 2: [ IP Address  ]
column 3: [       Device Name        ]
column 4: [    MAC Address]
column 1: [ 1 ]
column 2: [ 192.168.1.3 ]
column 3: [ ANDROID-FFFFFFFFFFFFFFFF ]
column 4: [ FF:FF:FF:FF:FF:FF]
column 1: [ 2 ]
column 2: [ 192.168.1.4 ]
column 3: [         XXXXXXX          ]
column 4: [ FF:FF:FF:FF:FF:FF]
column 1: [ 3 ]
column 2: [ 192.168.1.5 ]
column 3: [            --            ]
column 4: [ FF:FF:FF:FF:FF:FF]
column 1: [ 4 ]
column 2: [ 192.168.1.6 ]
column 3: [            --            ]
column 4: [ FF:FF:FF:FF:FF:FF]

1
投票

看看pandoc的filter功能:它允许您以编程方式更改文档,而无需自己解析表。可能最简单的选择是使用lua-filters,因为它们不需要外部程序,并且完全独立于平台。

这是一个过滤器,它作用于表体的每个单元格,忽略表头:

function Table (table)
  for i, row in ipairs(table.rows) do
    for j, cell in ipairs(row) do
      local cell_text = pandoc.utils.stringify(pandoc.Div(cell))
      local text_val = changed_cell(cell_text)
      row[j] = pandoc.read(text_val).blocks
    end
  end
  return table
end

其中changed_cell可以是lua函数(lua具有良好的built-in support for patterns)或通过awk管道输出的函数:

function changed_cell (raw_text)
  return pandoc.pipe('awk', {'YOUR AWK SCRIPT'}, raw_text)
end

以上是一个稍微单一的pandoc过滤器,因为过滤器通常不会对原始字符串起作用,而是对pandoc AST元素起作用。但是,上述情况应该适用于您的情况。

© www.soinside.com 2019 - 2024. All rights reserved.