linux 将HTML文件转换为管道('|')分隔文本文件

ldxq2e6h  于 2023-11-17  发布在  Linux
关注(0)|答案(3)|浏览(140)

我收到了一个巨大的HTML表数据,并已转换成管道分隔的文本文件与封闭字符作为单引号(')。我正在寻找一个shell脚本来做到这一点。
下面是示例html,

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>Data</title>
</head>
<body>
<table border=1>
<tr>
<td bgcolor=silver class='medium'>patientName</td>
<td bgcolor=silver class='medium'>Address</td>
<td bgcolor=silver class='medium'>Age</td>
</tr>

<tr>
<td class='normal' valign='top'>Sanju</td>
<td class='normal' valign='top'>My address, Pin:12345</td>
<td class='normal' valign='top'>1</td>
</tr>
</table>
</body></html>

字符串
下面是文本文件中预期输出,

|'patientName'|'Address'|'Age'
|'Sanju'|'My address, Pin:12345'|'1'


我试着用记事本手动完成,
1.已删除表、正文和html标记
1.将<td bgcolor=silver class='medium'>替换为|'
1.替换为\r\n '
1.已删除与.
对于较小的文件,它对我有用。但是,对于大文件,它需要时间和记事本
不工作。

ldioqlga

ldioqlga1#

**编辑:**正如评论中所指出的,HTML解析器将是一个更强大的工具来完成这项工作。而且,yikes!我只是重读了这个问题,并意识到你可能会处理相当敏感的数据。更有理由正确地做这件事。

要在shell中实现这一点,我们可以使用几个命令。
首先,sed

sed -n '/<table/,/<\/table>/p' input.html

字符串
这将读取一个名为input.html的文件,并删除任何不在<table>标记之间的内容。
然后我们可以将其传递给awk

awk '
BEGIN { RS = "</tr>"; FS = "\n"; OFS = "" }
{
    for (i = 1; i <= NF; i++) {
        gsub(/<[^>]*>/, "", $i);
        gsub(/^[ \t]+|[ \t]+$/, "", $i);
        if ($i != "") {
            printf("|'\''%s'\''", $i);
        }
    }
    if (NF > 0) {
        print "";
    }
}
' > output.txt


这将从每一行中删除HTML标记,然后用竖线和引号格式化和打印每个单元格,最后在每行末尾添加一个换行符。
要将所有这些放在一起,请创建一个名为convert.sh(或类似的东西)的脚本,并添加以下内容:

#!/bin/bash

sed -n '/<table/,/<\/table>/p' input.html | awk '
BEGIN { RS = "</tr>"; FS = "\n"; OFS = "" }
{
    for (i = 1; i <= NF; i++) {
        gsub(/<[^>]*>/, "", $i);
        gsub(/^[ \t]+|[ \t]+$/, "", $i);
        if ($i != "") {
            printf("|'\''%s'\''", $i);
        }
    }
    if (NF > 0) {
        print "";
    }
}
' > output.md


使文件可执行:

chmod +x convert.sh


然后像这样运行它:

./convert.sh


这是假设你在和input.html相同的目录下运行脚本。如果不是这样,相应地调整路径。
它还假设该表具有您的帖子中的格式(其中classbgcolor等属性是不相关的):

<table border=1>
<tr>
  <td bgcolor=silver class='medium'>patientName</td>
  <td bgcolor=silver class='medium'>Address</td>
  <td bgcolor=silver class='medium'>Age</td>
</tr>
<tr>
  <td class='normal' valign='top'>Sanju</td>
  <td class='normal' valign='top'>My address, Pin:12345</td>
  <td class='normal' valign='top'>1</td>
</tr>
<tr>
  <td class='normal' valign='top'>Jim</td>
  <td class='normal' valign='top'>München</td>
  <td class='normal' valign='top'>2</td>
</tr>
</table>


针对此脚本运行脚本可以得到:

|'patientName'|'Address'|'Age'
|'Sanju'|'My address, Pin:12345'|'1'
|'Jim'|'München'|'2'


希望这能满足你的要求,但如果不能,可以修改脚本以考虑任何偏差。
最后一点,请考虑对表使用(或至少注意)语义标记(例如<thead><tbody><tfoot>)。参见here

fquxozlt

fquxozlt2#

$ awk -F'>|<' '
   /<tr>/,/<\/tr>/ {
      if(NF==5) printf "|\47%s\47", $3
   } 
   /<\/tr>/{printf "\n"}
' file
|'patientName'|'Address'|'Age'
|'Sanju'|'My address, Pin:12345'|'1'

字符串

bwitn5fc

bwitn5fc3#

如果你的输入总是看起来和你在例子中显示的一样,那么使用GNU awk来处理多字符RS:

$ cat tst.awk
BEGIN {
    RS  = "</?tr[^>]*>"
    FS  = "</?td[^>]*>"
    OFS = "|"
    qt  = "\047"
}
(NR%2) == 0 {
    for ( i=2; i<NF; i+=2 ) {
        gsub(qt,"&&",$i)   # one way to handle embedded quotes
        out = (i>2 ? out OFS : "") qt $i qt
    }
    print out
}

字符串

$ awk -f tst.awk file
'patientName'|'Address'|'Age'
'Sanju'|'My address, Pin:12345'|'1'


如果我们在示例输入文件中将Sanju更改为Peter O'Toole,那么我们可以看到脚本如何按照CSV标准RFC 4180的要求将其加倍来处理嵌入的引号:

$ awk -f tst.awk file
'patientName'|'Address'|'Age'
'Peter O''Toole'|'My address, Pin:12345'|'1'


如果你真的想在每一个输出行的开头都有一个|,那么把(i>2 ? out OFS : "") qt $i qt改为(i>2 ? out : "") OFS qt $i qt
如果你决定要生成CSV而不是当前格式,只需更改OFSqt的值:

OFS = ","
    qt  = "\""


像所有不使用HTML解析器的答案一样,它是脆弱的。

相关问题