Jak wyodrębnić ciąg znaków według wzorca za pomocą GREP, REGEX lub PERL

Mam plik, który wygląda mniej więcej tak:

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

Muszę wyodrębnić cokolwiek z cudzysłowów, które następują po " name=", tj. content_analyzer , content_analyzer2 i content_analyzer_items.

Robię to na Linuksie, więc rozwiązanie wykorzystujące sed, perl, grep lub bash jest w porządku.

Author: ROMANIA_engineer, 2011-02-22

8 answers

Ponieważ musisz dopasować treść bez uwzględniania jej w wyniku (musi dopasować name=" ale nie jest to część pożądanego rezultatu) jakaś forma wymagane jest dopasowanie zerowej szerokości lub przechwytywanie grup. Można to zrobić łatwo za pomocą następujących narzędzi:

Perl

W Perlu można użyć opcji n do pętli linia po linii i wydruku zawartość grupy przechwytywania, jeśli pasuje:

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

GNU grep

Jeśli masz ulepszoną wersję grepa, takich jak GNU grep, możesz mieć dostępna jest opcja -P. Ta opcja włączy regex podobny do Perla, pozwala na użycie \K, który jest skrótem lookbehind. Zresetuje się pozycji meczu, więc wszystko przed nim jest zerową szerokością.

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

Opcja o sprawia, że grep drukuje tylko dopasowany tekst, zamiast cała linia.

Vim-Edytor Tekstu

Innym sposobem jest bezpośrednie użycie edytora tekstu. Z Vim, jednym z różne sposoby osiągnięcia tego byłoby kasowanie linii bez name= a następnie wyodrębnij zawartość z wynikowych linii:

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

Standardowy grep

Jeśli nie masz dostępu do tych narzędzi, z jakiegoś powodu, coś podobnie można było osiągnąć w przypadku standardowego grep. Jednak bez wyglądu wokół niego będzie wymagać trochę czyszczenia później:

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

Uwaga o zapisywaniu wyników

We wszystkich powyższych poleceniach wyniki będą wysyłane do stdout. On ważne dla pamiętaj, że zawsze możesz je zapisać, podłączając je do plik przez dodanie:

> result

Do końca komendy.

 121
Author: sidyll,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-17 15:12:54

Wyrażenie regularne będzie brzmiało:

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

Wtedy grupowanie będzie w \1

 5
Author: Matt Shaver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-22 16:39:26

Jeśli używasz Perla, pobierz Moduł do analizy XML: XML::Simple, XML:: Gałązka, lub XML:: LibXML. Nie wymyślaj koła od nowa.

 5
Author: shawnhcorey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-22 16:43:01

Parser HTML powinien być używany do tego celu, a nie do wyrażeń regularnych. Program Perla, który korzysta z HTML::TreeBuilder:

Program

#!/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>

Wyjście

content_analyzer
content_analyzer2
content_analyzer_items
 4
Author: Alan Haggai Alavi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-22 17:12:29

This could do it:

perl -ne 'if(m/name="(.*?)"/){ print $1 . "\n"; }'
 2
Author: Benoit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-22 16:39:07

Oto rozwiązanie przy użyciu 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
 1
Author: mitma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:49:36

UPS, Komenda sed musi oczywiście poprzedzać polecenie 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
 1
Author: mitma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-16 17:59:18

Jeśli struktura twojego xml (lub ogólnie tekstu) jest stała, najprostszym sposobem jest użycie cut. Dla konkretnego przypadku:

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 '"'
 0
Author: Carlos Lindado,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-01 22:56:02