2017-03-27 21 views
5

Mam ciągJak przechwytywać grupy dopasowań na przemian wyrażenia regularnego z podziałem?

my $foo = 'one#two#three!four#five#six'; 

z którego chcesz wyodrębnić części, które są rozdzielone albo przez # lub !. Jest to dość łatwe z split:

my @parts = split /#|!/, $foo; 

Dodatkowym wymogiem jest to, że również trzeba uchwycić wykrzykników. Dlatego starałem

my @parts = split /#|(!)/, $foo; 

jednak ta zwraca albo wartość undef lub wykrzyknik (który jest również jasno określone w specyfikacji Split).

Więc pozbyć się niechcianych undef wartości z grep:

my @parts = grep { defined } split /#|(!)/, $foo; 

to robi to, co chcę.

Jednak zastanawiałem się, czy mogę zmienić wyrażenie regularne w taki sposób, że nie muszę również wywoływać grep.

+5

Sugeruję, że _keeping_ 'grep' nie jest złą rzeczą - czyni to znacznie bardziej oczywistym, co robi twój kod. Na przykład. 'my @parts = grep {nie/^ # $ /} split/(# |!) /, $ foo;' – Sobrique

+2

+++ @Sobrique :) Po przeczytaniu mojego własnego kodu po pół roku pomaga, jeśli nie jest ' t obfuscated ... – jm666

Odpowiedz

5

Podczas korzystania split, możesz nie pomijaj pustych przechwytów po znalezieniu meczu (ponieważ w dopasowaniu jest zawsze tyle przechwyceń, ile jest zdefiniowanych w wyrażeniu regularnym). Można użyć dopasowanie podejście tutaj, choć:

my @parts = $foo =~ /[^!#]+|!/g; 

ten sposób można dopasować 1 lub więcej znaków innych niż ! i # (z [^!#]+ alternatywa) lub wykrzyknik, wielokrotnie (/g) .

2

Use „pusty ciąg następnie wykrzyknikiem lub pusty ciąg poprzedzony wykrzyknikiem” w miejscu drugiego alternatywa:

my @parts = split /#|(?=!)|(?<=!)/, $foo; 

Demo: https://ideone.com/6pA1wx

+2

Raczej '/ # | (? =!) | (? <=!) /' jeśli dobrze rozumiem pytanie, nie? – Dada

+0

@Dada: Tak, masz rację. Początkowo źle zrozumiałem pytanie. Zaktualizowano odpowiedź. –