我的txt文件中有以下内容:
<ol><li><b><a href="/page1/Mark_Yato" title="Mark Yato">Mark Yato</a> ft. MarkAm & <a href="/page1/Giv%C4%93on" title="Givēon">Givēon</a> - <a href="/page1/Mark_Yato:Thuieo" title="Mark Yato:Thuieo">Thuieo</a> (7)</b></li>
<li><b><a href="/page1/The_Central" title="The Central">The Central</a> - <a href="/page1/The_Central:AHTIOe oie" title="The Central:AHTIOe oie">AHTIOe oie</a> (7)</b></li>
<li><b><a href="/page1/Taa_Too_A" title="Taa Too A">Taa Too A</a> - <a href="/page1/Taa_Too_A:ryhwtyw w" title="Taa Too A:ryhwtyw w">ryhwtyw w</a> (8)</b></li>
并试图使其输出如下:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
为了实现这一目标,我想我会尝试删除“<”、“>”以及它们之间的所有内容,这样就只剩下我想要获取的列表。
我已经尝试过以下 sed 命令:
sed 's/<[^()]*>//g'
但这仅输出以下内容:
(7)
(7)
(8)
我做错了什么以及如何修复 sed 命令或将其转换为 awk(如果它更适合)?
答案1
用正则表达式解析标记是出了名的有问题。
虽然示例数据不是问题,但尖括号可能会出现在标签属性、注释和可能的其他位置中,从而使匹配 from 的正则表达式变得<
不>
可靠。
您应该求助于实现标记解析器的工具。
例如,使用潘多克(版本> = 2.8)与您的示例数据(不添加缺少的</ol>
标签):
$ pandoc -f html -t plain file
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
然后,您可以轻松地将此输出作为常规文本进行后处理,以删除空行和其他不需要的部分:
$ pandoc -f html -t plain file |
sed -e '/^$/d' -e 's/[[:blank:]]*([[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
请注意,在 2.8 版本之前,pandoc
用于在生成格式输出时将任何强调文本转换为全部大写plain
。列表项中的标签<b>
将触发此行为(更多信息请参见变更日志或相关的犯罪在 GitHub 上)。
根据您的实际输入数据,解决方法可能是显式使用markdown
as的输入格式:pandoc
pandoc -f markdown -t plain file
或者隐式地考虑到它pandoc
自动默认为 ( pandoc -t plain file
)。
答案2
你就快到了 - 正则表达式匹配是“贪婪的”,所以你需要告诉模式,>
模式内不允许有结束字符。换句话说,[^()]*
模式内的部分将“贪婪地”匹配尽可能多的文本。如果您不告诉模式>
从模式的这一部分中排除结束语,则正则表达式使用的开始<
和结束>
不一定是从 HTML 角度来看配对的。
使用这个代替:
sed -e 's/<[^>]*>//g'
这会强制正则表达式删除每个 HTML 标签,而不是删除结尾处以及<
中间有和的较大文本块。>
<
>
答案3
您可以使用php
剥离所有 HTML 标签并将 HTML 实体转换回普通字符:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);'
Mark Yato ft. MarkAm & Givēon - Thuieo (7)
The Central - AHTIOe oie (7)
Taa Too A - ryhwtyw w (8)
要另外删除空格(空格、制表符),后跟一个开头(
,后跟一个或多个数字以及)
以 结尾的行的结尾sed
:
$ <file php -r 'echo htmlspecialchars_decode(strip_tags(file_get_contents("php://stdin")), ENT_HTML5);' |
sed 's/[[:blank:]]*([[:digit:]][[:digit:]]*)$//'
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w
答案4
使用xmlstarlet
:
xmlstarlet fo -H file |
xmlstarlet sel -E latin1 -t -v '//li' -nl 2>/dev/null |
xmlstarlet unesc | sed 's/ [^ ]*$//'
这用于xmlstarlet
将 HTML 片段转换为格式良好的 HTML 文档(第一个命令)。然后它提取每个节点的值li
(第二个命令)。最后,它解码任何 HTML 实体(&
例如)。最后的sed
命令只是删除每行最后一个空格之后的所有内容(括号中的数字不应成为输出的一部分)。
问题中给出的文档的输出:
Mark Yato ft. MarkAm & Givēon - Thuieo
The Central - AHTIOe oie
Taa Too A - ryhwtyw w