提问人:wrangler 提问时间:2/23/2011 最后编辑:Michaelwrangler 更新时间:11/26/2019 访问量:302991
如何使用 grep、regex 或 perl [duplicate] 按照模式提取字符串
How to extract string following a pattern with grep, regex or perl [duplicate]
问:
社区去年审查了是否重新讨论这个问题,并关闭了它:
重复这个问题已经得到回答,不是唯一的,也没有与另一个问题区分开来。
我有一个文件,看起来像这样:
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
我需要提取后面引号中的任何内容,即 和 。name=
content_analyzer
content_analyzer2
content_analyzer_items
我是在 Linux 机器上执行此操作的,因此使用 sed、perl、grep 或 bash 的解决方案就可以了。
答:
这可以做到:
perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
正则表达式为:
.+name="([^"]+)"
然后分组将在 \1
如果您使用的是 Perl,请下载一个模块来解析 XML:XML::Simple、XML::Twig 或 XML::LibXML。 不要重新发明轮子。
评论
<type="global"
为此,应使用 HTML 解析器而不是正则表达式。一个使用 HTML::TreeBuilder
的 Perl 程序:
程序
#!/usr/bin/env perl
use strict;
use warnings;
use HTML::TreeBuilder;
my $tree = HTML::TreeBuilder->new_from_file( \*DATA );
my @elements = $tree->look_down(
sub { defined $_[0]->attr('name') }
);
for (@elements) {
print $_->attr('name'), "\n";
}
__DATA__
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
输出
content_analyzer
content_analyzer2
content_analyzer_items
由于您需要匹配内容而不将其包含在结果中(必须
匹配,但它不是所需结果的一部分)某种形式的
需要零宽度匹配或分组捕获。这是可以做到的
使用以下工具轻松:name="
Perl的
使用 Perl,您可以使用该选项逐行循环并打印
捕获组的内容(如果匹配):n
perl -ne 'print "$1\n" if /name="(.*?)"/' filename
GNU grep
如果你有一个改进的 grep 版本,比如 GNU grep,你可能有
可用的选项。此选项将启用类似 Perl 的正则表达式,
允许您使用哪个是速记后视。它将重置
匹配位置,因此它之前的任何内容都是零宽度。-P
\K
grep -Po 'name="\K.*?(?=")' filename
该选项使 grep 仅打印匹配的文本,而不是
整条线。o
Vim - 文本编辑器
另一种方法是直接使用文本编辑器。使用 Vim,其中之一
实现此目的的各种方法是删除不带的行,然后从生成的行中提取内容:name=
:v/.*name="\v([^"]+).*/d|%s//\1
标准 grep
如果您由于某种原因无法访问这些工具,请 使用标准 GREP 也可以实现类似的效果。然而,没有外观 围绕它稍后将需要进行一些清理:
grep -o 'name="[^"]*"' filename
关于保存结果的说明
在上面的所有命令中,结果将被发送到 。它
重要的是要记住,您始终可以通过将其管道连接到
文件附加:stdout
> result
到命令的末尾。
评论
grep
grep -Po '.*name="\K.*?(?=".*)'
.*
"
\K
.*
grep -Po '(?<=name=").*?(?=")'
\K
[^"]*
.*?
\K
.*
.*?
这是一个使用HTML tidy和xmlstarlet的解决方案:
htmlstr='
<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>
'
echo "$htmlstr" | tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null |
sed '/type="global"/d' |
xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
哎呀,sed 命令当然必须在 tidy 命令之前:
echo "$htmlstr" |
sed '/type="global"/d' |
tidy -q -c -wrap 0 -numeric -asxml -utf8 --merge-divs yes --merge-spans yes 2>/dev/null |
xmlstarlet sel -N x="http://www.w3.org/1999/xhtml" -T -t -m "//x:table" -v '@name' -n
如果 xml(或一般文本)的结构是固定的,最简单的方法是使用 .对于您的具体情况:cut
echo '<table name="content_analyzer" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer2" primary-key="id">
<type="global" />
</table>
<table name="content_analyzer_items" primary-key="id">
<type="global" />
</table>' | grep name= | cut -f2 -d '"'
评论