我有一个 HTML 文件,想提取之间的文本 <li></li> 标签。当然有一百万种方法可以做到这一点,但我认为更多地养成在简单的 shell 命令中执行此操作的习惯会很有用:

awk '/<li[^>]+><a[^>]+>([^>]+)<\/a>/m' cities.html

问题是,这打印 一切 而我只是想打印括号中的匹配项—— ([^>]+) --要么awk不支持这个,要么我无能。后者的可能性似乎更大。如果您想将提供的正则表达式应用于文件并仅提取指定的匹配项,您会怎么做?我已经知道六种其他方法,但我不想让 awk 赢得这一轮;)

编辑:数据结构不佳,因此使用位置匹配($1, $2, etc.)是不行的。

有帮助吗?

解决方案

这是你的脚本,如果你能得到你想要的东西(这意味着<li><a>标签是在同一行);

$ cat test.html | awk 'sub(/<li[^>]*><a[^>]*>/,"")&&sub(/<\/a>.*/,"")'

$ cat test.html | gawk '/<li[^>]*><a[^>]*>(.*?)<\/a>.*/&&$0=gensub(/<li[^>]*><a[^>]*>(.*?)<\/a>.*/,"\\1", 1)'

第一个是为每一个AWK,第二个是用于GNU AWK。

其他提示

如果你想这样做,在一般情况下,你的清单标签可以包含任何合法的HTML标记,然后awk是错误的工具。这项工作的合适的工具将是一个HTML解析器,你可以信任得到正确所有的HTML解析的小细节,包括HTML和畸形HTML的变体。

如果您是一个特例,在那里你可以控制HTML格式这样做,那么你可能能够使awk为你工作。例如,假设你能保证每个列表元素从未占据多于一行,总是与在同一行</li>终止,决不会包含任何标记(如包含列表的列表),那么你可以使用awk来做到这一点,但你需要编写第一查找包含列表元素线整体awk程序,然后使用其他awk命令,找到刚才子你感兴趣的内容。

但在一般情况下,awk是这个职位的错误的工具。

gawk -F'<li>' -v RS='</li>' 'RT{print $NF}' file

工作得很好我。

我发现有几个问题:

  • 该模式有一个尾随“m”,这对于 Perl 中的多行匹配很重要,但 Awk 不使用与 Perl 兼容的正则表达式。(至少,标准(非 GNU)awk 没有。)
  • 忽略这一点,该模式似乎搜索“开始列表项”,后跟锚点“<a>' 到 '</a>',而不是最终列表项。
  • 您搜索任何不是 '>' 作为锚点的主体;这并不是自动错误的,但搜索任何不是 ' 的内容可能更常见<',或者任何两者都不是的东西。
  • awk 不进行多行搜索。
  • 在 awk 中,'$1' 表示第一个字段,其中字段由字段分隔符分隔,默认为空格。
  • 经典中 nawk (如记录在'sed & awk' 书籍年份 1991)没有适当的机制将子字段从比赛中拉出,等等。

目前尚不清楚 Awk 是否适合这项工作。事实上,尚不完全清楚正则表达式是否适合这项工作。

真的不知道awk中,如何对Perl语言的呢?

tr -d '\012' the.html | perl \
-e '$text = <>;' -e 'while ( length( $text) > 0)' \
-e '{ $text =~ /<li>(.*?)<\/li>(.*)/; $target = $1; $text = $2; print "$target\n" }'

1)从文件中删除新行,通过perl的管

2)初始化完整的文本的变量,启动一个循环,直到文本消失

3)做一个“非贪婪”匹配的东西通过列表项标签界定,保存并打印目标,设置为下一个通

有意义吗? (警告,没有尝试这个代码我自己,需要尽快回家......)

P.S。 - “perl的-n” 是在awk(NAWK?)模式。 Perl是很大程度上awk中的超集,所以我从来费心去学习awk中。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top