Как бы я сопоставил переменное многострочное perl регулярное выражение с различными правилами - PullRequest
0 голосов
/ 07 января 2020

API синтаксического анализатора (который мне не разрешено изменять) дает мне строку этого вида:

    var1    var2  \
var2continued var2continued   \\\
var2continued
var3
var3continued \

var3continued

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

$1 = "var1";
$2 = "var2  
var2continued var2continued   \\
var2continued"
$3 = "var3
var3continued \

var3continued"

По сути, первая переменная - это первое непробельное слово после 1 или более пробелов и заканчивается при обнаружении пробела.

Вторая переменная начинается с первого непробельного символа после первой переменной до конца строки. Если последним символом является «\», добавьте следующую строку ко второй переменной (не обрезайте пробел между последним символом на строке курсора и «\»). «\» не должен захватывать следующую строку, но возвращает оба «\» (без escape). Обрезать только пробел для последней строки.

Третья переменная - это все, что находится после второй переменной.

До сих пор я мог придумать это регулярное выражение, которое работает только с одной строкой для var2 и var3

$my_re = qr/\s+(\S+)\s+(\S+)\s+[\n](.*)/

$text =~ /$my_re/

Ответы [ 3 ]

4 голосов
/ 07 января 2020

Первое слово, затем все до новой строки, непосредственно предшествующей без косой черты; затем все остальное

/\s+ (\S+) \s+ (.*?[^\\]) \n (.*)/xs;

Модификатор /s делает так, чтобы . также соответствовал символу новой строки, что здесь критично (обычно это не так). Модификатор /x позволяет игнорировать буквенные пробелы, чтобы мы могли сделать его более читабельным.


Пример программы

use warnings;
use strict;
use feature 'say';

my $v = 
q(    var1    var2  \
var2continued var2continued   \\\
var2continued
var3
var3continued \

var3continued);

$v =~ /\s+ (\S+) \s+ (.*?[^\\]) \n (.*)/xs;

say "\"$1\"";  say '---';
say "\"$2\"";  say '---';
say "\"$3\""; 

print

"var1"
---
"var2  \
var2continued var2continued   \\
var2continued"
---
"var3
var3continued \

var3continued"
1 голос
/ 07 января 2020

Попробуйте следующий фрагмент кода (мой взгляд на проблему)

use strict;
use warnings;

my $str = do { local $/; <DATA> };

print "INPUT:\n[$str]\n";

$str =~ /(\w+)\s+(.*?\\\\\\\s*\w+)\n(.+)/s;
#$str =~ /(\w+)\s+((?:.*?)\\\\\\\s+(?:\w+)?)\n(.+)/s;

print "\n1: [$1]";
print "\n2: [$2]";
print "\n3: [$3]";

__DATA__
    var1    var2  \
var2continued var2continued   \\\
var2continued
var3
var3continued \

var3continued

output

INPUT:
[    var1    var2  \
var2continued var2continued   \\\
var2continued
var3
var3continued \

var3continued
]

1: [var1]
2: [var2  \
var2continued var2continued   \\\
var2continued]
3: [var3
var3continued \

var3continued
]
0 голосов
/ 08 января 2020

Ни один из ответов не работал для всех случаев (2 и 3 не являются обязательными). У меня была небольшая проблема, когда парсер добавлял пробел после backsla sh.

. Я разбил текст на массив строк. Затем разделите его на две части (1 и 2 вместе и 3 отдельно). Затем я разделил его на первую часть. Мой настоящий код разделен на несколько функций, но я упростил ниже:

my $empty_re = qr/^\s*$/;
my $def_re = qr/(.*?)((?:\\{2})*)(\\?)\s*$/;
my $dual_token_re = qr/\s*(\S+)\s*(.*)/s;
$text= "place text here"
my @lines = split /\n/, $text;
my $i;
my $j;
my $def = "";
my $other;
# Get start capture
for($i=0;$i<=$#lines;$i++){
    last if !($lines[$i] =~ /$empty_re/);
}

# Start definition capture
for($j=$i;$j<=$#lines;$j++) {
    $lines[$j] =~ s/$def_re/$1$2/; # remove ending backquote if odd
    last if !$3; # break if even backquotes
}
$def = join "\n", @lines[$i..$j];
$j++;

# Get remaining text
if ($j <= $#lines) {
    $other = join "\n", (splice @lines, $j);
}

# $def has 1 and 2, $other has 3

$def =~ /$dual_token/
# now $1 and $2 has 1 and 2, $other has 3

...