Совпадение регулярных выражений на нескольких разделенных символах - PullRequest
4 голосов
/ 24 мая 2009

В этой строке:

"<0> << 1 >> <2 >> <3> <4>"

Я хочу сопоставить все экземпляры "<\ d {1,2}>", за исключением тех, которые мне удалось избежать с дополнительным набором треугольных скобок, например, я хочу сопоставить 0,2,3,4, но не 1 Например:

" <0> << 1 >> <2> > <3> <4> "

Я хочу сделать это в одном регулярном выражении, но лучшее, что я могу получить, это:

(^ | [^ \ <]) \ <> ([^ (<1> \ d {1,2})?>] | $)

Что будет соответствовать 0,3,4, но не 2, например ::1010 *

" <0> << 1 >> <2 >> <3> <4> "

Кто-нибудь знает, как это можно сделать с помощью одного регулярного выражения?

Ответы [ 6 ]

5 голосов
/ 24 мая 2009

Вы также можете попробовать условия : (?(?<=<)(<\d{1,2}>(?!>))|(<\d{1,2}>))

2 голосов
/ 24 мая 2009

Вы можете посмотреть отрицательное утверждение нулевой ширины :

(?<!<)<\d{1,2}>
1 голос
/ 24 мая 2009

Предполагая, что с входным набором

 "<0> <<1>> <2>> <3> <4><<5>"

мы хотим соответствовать 0, 2, 3, 4 и 5.

Проблема заключается в том, что вам нужно использовать упреждающий просмотр нулевой ширины и упреждающий просмотр нулевой ширины, но есть три варианта для сопоставления: '<', '>' и '', и один не соответствует '<>'. Кроме того, если вы хотите иметь возможность извлекать помеченные выражения, чтобы можно было сопоставлять совпадения с массивом, вам следует избегать пометки вещей, которые вам не нужны. Итак, я закончил с не элегантным

use Data::Dumper;

my $a = "<0> <<1>> <2>> <3> <4><<5>";

my $brace_pair = qr/<[^<>]+>/;
my @matches = $a =~ /(?:(?<!<)$brace_pair(?!>))|(?:$brace_pair(?!>))|(?:(?<!<)$brace_pair)/g;

print Dumper(\@a);

Если вы хотите втиснуть это в одно выражение - вы могли бы.

0 голосов
/ 26 мая 2009

Вот быстрый и простой способ сделать это с помощью Perl.

use strict;
use warnings;

my $str = "<0> <<1>> <2>> <3> <4>";
my @array = grep {defined $_} $str =~ /<<\d+>>|<(\d+)>/g;

print join( ', ', @array ), "\n";
0 голосов
/ 25 мая 2009

В случае, если вы используете разновидность регулярных выражений (например, Java), которая поддерживает обходные пути, но не условия, вот другой подход:

(?=(<\d{1,2}>))(?!(?<=<)\1(?=>))\1

Первое предпросмотр гарантирует, что вы находитесь в начале тега и захватывает его для дальнейшего использования. Подвыражение во втором заглядывании снова совпадает с тегом, но только если ему предшествует <, а затем >. Делая это отрицательным прогнозом, вы получите семантику НЕ (x И y), которую вы ищете. Наконец, второй \1 снова совпадает с тегом, на этот раз по-настоящему (т.е. не в обходном порядке).

Кстати, я мог бы использовать > вместо (?=>) во втором прогнозе, но я думаю, что этот способ легче читать и лучше выражает мои намерения.

0 голосов
/ 24 мая 2009

Вот альтернатива одному регулярному выражению. Разбейте его на список на границе >< и затем исключите <...>.

#!/usr/bin/perl -lw

$s = "<0> <<1>> <2>> <3> <4>";

print join " ",
      map { /(\d+)/; $1 }
      grep !/^<.*>$/,
      split />\s*</, $s;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...