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.
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.
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
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.
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
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"; }'
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
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
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 '"'
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