106

我有一个看起来像这样的文件:

    <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_analyzercontent_analyzer2content_analyzer_items

我在 Linux 机器上执行此操作,因此使用 sed、perl、grep 或 bash 的解决方案很好。

4

8 回答 8

200

由于您需要匹配内容而不将其包含在结果中(必须匹配name=" 但它不是所需结果的一部分),因此需要某种形式的零宽度匹配或组捕获。这可以使用以下工具轻松完成:

Perl

使用 Perl,您可以使用n 选项逐行循环并打印捕获组的内容(如果匹配):

perl -ne 'print "$1\n" if /name="(.*?)"/' filename

GNU grep

如果您有 grep 的改进版本,例如 GNU grep,您可能有可用的 -P选项。此选项将启用类似 Perl 的正则表达式,允许您使用\K它是一种速记的lookbehind。它将重置匹配位置,因此它之前的任何内容都是零宽度。

grep -Po 'name="\K.*?(?=")' filename

o 选项使 grep 仅打印匹配的文本,而不是整行。

Vim - 文本编辑器

另一种方法是直接使用文本编辑器。使用 Vim,实现此目的的各种方法之一是删除没有的行 name=,然后从结果行中提取内容:

:v/.*name="\v([^"]+).*/d|%s//\1

标准 grep

如果由于某种原因您无法访问这些工具,则可以使用标准 grep 实现类似的功能。但是,如果不环顾四周,以后需要进行一些清理:

grep -o 'name="[^"]*"' filename

关于保存结果的说明

在上面的所有命令中,结果将被发送到stdout. 重要的是要记住,您始终可以通过将其管道附加到文件来保存它们:

> result

到命令的末尾。

于 2011-02-22T17:21:05.513 回答
5

正则表达式将是:

.+name="([^"]+)"

然后分组将在 \1

于 2011-02-22T16:39:26.443 回答
5

如果您使用 Perl,请下载一个模块来解析 XML:XML::SimpleXML::TwigXML::LibXML。不要重新发明轮子。

于 2011-02-22T16:43:01.653 回答
5

应为此目的使用 HTML 解析器而不是正则表达式。一个 Perl 程序,它使用HTML::TreeBuilder

程序

#!/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
于 2011-02-22T17:12:29.427 回答
2

这可以做到:

perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
于 2011-02-22T16:39:07.423 回答
2

这是使用 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
于 2011-03-16T17:49:36.630 回答
1

糟糕, 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
于 2011-03-16T17:59:18.213 回答
0

如果您的 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 '"'
于 2017-12-01T22:56:02.350 回答