提问人:Sooraj P George 提问时间:11/16/2023 最后编辑:Sooraj P George 更新时间:11/22/2023 访问量:99
转换 HTML 文件 to Pipe('|')带分隔符的文本文件
Convert HTML File to Pipe('|') Delimited Text file
问:
我收到了一个巨大的 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'
我尝试使用Notepad ++手动完成,
- 删除了表格、正文和 html 标签
- 替换为 |'
<td bgcolor=silver class='medium'>
- 将 \r\n 替换为
- 已删除和 .
对于较小的文件,它对我有用。但是,对于大文件,这需要时间,而且Notepad ++不起作用。
答:
编辑:正如评论中所指出的,HTML 解析器将是一个更强大的工具。还有,哎呀!我只是重新阅读了这个问题,并意识到您可能正在处理相当敏感的数据。更有理由正确地做到这一点。
要在 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
它还假定该表格具有您帖子中的格式(因此属性(例如 or 不相关):class
bgcolor
<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>
更新
更新了脚本以考虑换行符:
#!/bin/bash
sed -n '/<table/,/<\/table>/p' input.html | awk '
BEGIN { RS = "</tr>"; FS = "<td[^>]*>"; OFS = "" }
{
if (NF > 1) {
printf("|");
for (i = 2; i <= NF; i++) {
gsub(/<[^>]*>/, "", $i);
gsub(/\n/, " ", $i);
gsub(/^[ \t]+|[ \t]+$/, "", $i);
printf("'"'"%s"'"'", $i);
if (i < NF) {
printf("|");
}
}
print "";
}
}
' > output.txt
评论
xmlstarlet
<br>
$ 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'
如果您的输入始终与您在示例中显示的完全相同,那么将 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'
如果我们在示例输入文件中更改为,那么我们可以看到脚本如何按照 CSV 标准 RFC 4180 的要求加倍来处理嵌入的引号:Sanju
Peter O'Toole
$ awk -f tst.awk file
'patientName'|'Address'|'Age'
'Peter O''Toole'|'My address, Pin:12345'|'1'
如果您确实想要在每个输出行的开头更改为 a。(i>2 ? out OFS : "") qt $i qt
(i>2 ? out : "") OFS qt $i qt
|
如果您决定要生成 CSV 而不是当前格式,只需更改 和 的值:OFS
qt
OFS = ","
qt = "\""
像所有不使用 HTML 解析器的答案一样,它是脆弱的。
评论
td
'
foo'bar
'foo'bar'
|
'
,
"
|
|