一口气匹配线条并提取内容

一口气匹配线条并提取内容

我想找到带有 和 的行h2p获取标签之间的内容......

<main>Nothing</main>
<h2>Hello</h2><p>World</p>
<h2>Bells</h2><p>Walls</p>
<h2>Jelly</h2><p>Minus</p>
<p>Fluff</p>

...进入制表符分隔列表:

Hello World
Bells Walls
Jelly Minus

我目前使用:

grep -E "<h2>(.*)<\/h2><p>(.*)<\/p>" | sed -E "s/<h2>(.*)<\/h2><p>(.*)<\/p>/\1 \2/"

grep <pattern>但是,我发现必须先执行,这有点烦人sed <the same pattern>。是否可以使用单个实用程序执行此操作,仅使用一次模式?

答案1

使用 XML 解析器确实是个好主意,但如果由于某种原因无法使用解析器(文件格式不正确、没有安装任何解析器等),则可以使用 PERL 来实现此目的:

$ perl -ne 'if(/<h2>(.*?)<\/h2><p>(.*?)<\/p>/){print "$1\t$2\n"}' filename.ext
Hello   World
Bells   Walls
Jelly   Minus

我更喜欢使用惰性匹配,这样我就不会得到意想不到的结果:

测试.txt

<h1>Nothing</h1>
<h2>Hello</h2><p>World</p><h2>Goodbye</h2><p>Earth</p>
<h2>Bells</h2><p>Walls</p>
<h2>Jelly</h2><p>Minus</p>
<h3>Zip</h3>

$ perl -ne 'if(/<h2>(.*?)<\/h2><p>(.*?)<\/p>/){print "$1\t$2\n"}' test.txt
Hello   World
Bells   Walls
Jelly   Minus
$ perl -ne 'if(/<h2>(.*)<\/h2><p>(.*)<\/p>/){print "$1\t$2\n"}' test.txt
Hello</h2><p>World</p><h2>Goodbye       Earth
Bells   Walls
Jelly   Minus

正如您所看到的,仅使用正则表达式无法获得特定于域的工具所能获得的所有情况。如果您对此表示同意,那就没问题;请注意,如果输入与您的模式不完全匹配,您可能会得到不准确的结果!

答案2

正确的方法是与xmlstarlet工具(用于解析xml/html数据):

xmlstarlet sel -t -m '//h2' -v 'concat(., "'$'\t''", ./following-sibling::p)' -n file

输出:

Hello   World
Bells   Walls
Jelly   Minus

答案3

对于您使用的包含未加引号的正则表达式(),需要扩展正则表达式语法(或将每个(and替换)\(and \))。这很简单。

并且,可能会避免使用过多的贪婪匹配[^<]而不是点。

当然,您可以设置一个变量并使用引号进行操作仅有的sed:

$ a='<h2>([^<]*)<\/h2><p>([^<]*)<\/p>'                                                                    
$ sed -nE '/'"$a"'/s/'"$a"'/\1 \2/p' infile

但它会变得更好,因为这可以简化。 Sed 会记住最后使用的正则表达式,左侧s//(空) 就足够了。

$ sed -nE '/'"$a"'/s//\1 \2/p' infile

或者,没有变量:

$ sed -nE '/<h2>([^<]*)<\/h2><p>([^<]*)<\/p>/s//\1 \2/p' infile
Hello World
Bells Walls
Jelly Minus

答案4

可能的解决方案通过sed

sed 's/<[^13>]*>/ /g' test | sed 's/<h[13]>.*<\/h[13]>//' <file>

 Hello  World
 Bells  Walls
 Jelly  Minus

其次sed只是删除不必要的标签(<h1><h3>)。

图案说明:

/<[^13>]*>/ /- 搜索*文本中以 开头<和结尾的任何符号>。但在标签之间的符号13 一定不^) 出席。

相关内容