Как я могу иметь дополнительные совпадения в регулярном выражении Perl? - PullRequest
1 голос
/ 05 июня 2009

У меня есть строка, которую я прочитал из файла конфигурации. Структура строки следующая:

(long_string)long_string(long_string)

Любые пункты в скобках, включая сами скобки, являются необязательными. У меня есть следующее регулярное выражение, соответствующее всей строке, но я не могу понять, как сделать некоторые части регулярного выражения необязательными с помощью «?».

Вот несколько допустимых строк для ввода

(a)like(1)
like(very long string here)
like

Вот мое регулярное выражение, совпадающее только с первым;

^\((?<short>.*)\)(?<text>.*)\((?<return>.*)\)$

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

Ответы [ 5 ]

5 голосов
/ 05 июня 2009

Обведите два подшаблона несоответствующими группами (?:expr) и сделайте их необязательными:

^(?:\((?<short>.*)\))?(?<text>.*)(?:\((?<return>.*)\))?$

И если возможно, сделайте универсальное выражение .* более конкретным, возможно, с [^()]+:

^(?:\((?<short>[^()]+)\))?(?<text>[^()]+)(?:\((?<return>[^()]+)\))?$
4 голосов
/ 05 июня 2009

Используя приведенный ниже код, вы всегда получите массив @matches, состоящий из трех элементов. Если одна из дополнительных частей не совпадает, соответствующая запись будет неопределенной.

#!/usr/bin/perl

use strict;
use warnings;

my $optional = qr/(?:\(([^)]+?)\))?/;
my $required = qr/([^()]+)/;

while ( my $line = <DATA> ) {
    chomp $line;
    last unless $line =~ /\S/;

    if ( my @matches = ($line =~ /$optional$required$optional/) ) {
        no warnings 'uninitialized';
        print "---$_---\n" for @matches;
    }
}

__DATA__
(a)like(1)
like(very long string here)
like
1 голос
/ 05 июня 2009

Что бы я сделал, это обернул (и) членами вашей группы, так что вместо

\((?<short>.*)\)

изменить на:

(\(<short>.*\))

Таким образом, он будет соответствовать () и внутреннему тексту. Затем, если они присутствуют, используйте другое регулярное выражение для исключения скобок.

Я не очень знаком с синтаксисом именованных совпадений, поэтому групповой синтаксис может быть отключен, но вы должны понять.

0 голосов
/ 05 июня 2009

Ну, просто сделайте их необязательными, тогда:

^(?<short>\(.*\))?(?<text>.*)(?<return>\(.*\))?$

Я не большой поклонник именованных снимков, они, как правило, делают его более сложным, чем он (по крайней мере, для меня). Также я рекомендую не использовать ".*". Мое предложение:

^(\([^)]*\))?([^(]*)(\([^)]*\))?$

и перейдите к группе совпадений 2. Но если вы настаиваете на использовании именованных захватов:

^(?<short>\([^)]*\))?(?<text>[^(]*)(?<return>\([^)]*\))?$
0 голосов
/ 05 июня 2009

Дайте это попробовать ...

string[] strings = new string[] { "(a)like(1)", "like(very long string here)", "like" };
foreach (string s in strings)
{
    System.Text.RegularExpressions.Match match = System.Text.RegularExpressions.Regex.Match(s, @"^(\((?<short>.)\))?(?<text>.+)?(\((?<return>.+)\))?$");
    if (match.Success)
    {
        // do logic to handle the match
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...