2014-11-10 2 views
-1

Я пытаюсь определить правило в flex, которое будет захватывать «многострочную строку».
Многострочная строка - это строка, которая начинается с трех апострофов: ''', заканчивается тремя апострофами и может охватывать несколько строк.
Например:Как написать следующее регулярное выражение в Flex?

'''This is 
an example of 
a multiline 
string''' 

Так что моя попытка это было так:

%{ 
#include<iostream> 
using std::cout; 
using std::endl; 

%} 

MULTI_LN_STR '''(.|\n)*''' 

%% 

{MULTI_LN_STR} {cout<<"GotIt!";} 

%% 

int main(int argc, char* argv[]) { 

    yyin=fopen("test.txt", "r"); 

    if (!yyin) { 
     cout<<"yyin is NULL"<<endl; 
     return 1; 
    } 

    yylex(); 
    return 0; 
} 

Который работает для ввода:

'''This is 
a multi 
line 
string!''' 

This is 
some random 
text 

Выход есть:

GotIt! 

This is 
some random 
text 

, но не работает (или, чтобы быть более точным, производит неверный вывод) для этого входа:

'''This is 
a multi 
line 
string!''' 

This is 
some random 
text 

'''and this 
is another 
multiline 
string''' 

Который производит:

GotIt! 

Эта причина, потому что мое правило говорит:
«сканирование трех апострофов, за которым следует любой возможный символ, за которым следуют три апострофа»,
, но, скорее, он должен сказать:
«Сканирование трех апострофов, за которыми следует любой возможный характер er кроме трех апострофов, а затем три апострофа ».

Как я могу это сделать?

ответ

2

Для простого отрицания, как это, относительно легко построить регулярное выражение:

"'''"([^']|'[^']|''[^'])*"'''" 
-2

кажется, поддерживает Квант диапазон {х, у} построить,
так это работает, и, конечно, быстрее, чем чередования.
Если у вас большие струны, это путь.

'''[^']*(?:[']{1,2}[^']+)*'''

''' 
[^']* 
(?: [']{1,2} [^']+)* 
''' 

контрольные показатели: Чередование против NO-чередования

----------------------------- 
'''Set 1 - this 
is another 
multiline 
string''' 
Regex_FAST (?-xism:'''[^']*(?:[']{1,2}[^']+)*''') 
    -took: 0.811201 wallclock secs (0.81 usr + 0.00 sys = 0.81 CPU) 

'''Set 1 - this 
is another 
multiline 
string''' 
Regex_ALT (?-xism:'''(?:[^']|'[^']|''[^'])*''') 
    -took: 1.4971 wallclock secs (1.50 usr + 0.00 sys = 1.50 CPU) 

----------------------------- 
'''Set 2 - this 
is' another 
mul'tiline 
st''ring''' 
Regex_FAST (?-xism:'''[^']*(?:[']{1,2}[^']+)*''') 
    -took: 0.935462 wallclock secs (0.94 usr + 0.00 sys = 0.94 CPU) 

'''Set 2 - this 
is' another 
mul'tiline 
st''ring''' 
Regex_ALT (?-xism:'''(?:[^']|'[^']|''[^'])*''') 
    -took: 1.85556 wallclock secs (1.86 usr + 0.00 sys = 1.86 CPU) 

Benchmark кода:

use strict; 
use warnings; 
use Benchmark ':hireswallclock'; 

my ($t0,$t1); 
my @dataset = (
    "'''Set 1 - this\nis another\nmultiline\nstring'''", 
    "'''Set 2 - this\nis' another\nmul'tiline\nst''ring'''"); 

my $regex_FAST = qr/'''[^']*(?:[']{1,2}[^']+)*'''/; 
my $regex_ALT = qr/'''(?:[^']|'[^']|''[^'])*'''/; 

for my $data (@dataset) 
{ 
    print "-----------------------------\n"; 

    ## 
    while ($data =~ /$regex_FAST/g){ print "$&\n"; }; 
    $t0 = new Benchmark; 
    for my $cnt (1 .. 500_000) { 
     while ($data =~ /$regex_FAST/g){ }; 
    } 
    $t1 = new Benchmark; 
    print " Regex_FAST $regex_FAST\n -took: ", timestr(timediff($t1, $t0)), "\n\n"; 

    ## 
    while ($data =~ /$regex_ALT/g){ print "$&\n"; }; 
    $t0 = new Benchmark; 
    for my $cnt (1 .. 500_000) { 
     while ($data =~ /$regex_ALT/g){ }; 
    } 
    $t1 = new Benchmark; 
    print " Regex_ALT $regex_ALT\n -took: ", timestr(timediff($t1, $t0)), "\n\n"; 
} 
+1

Почему вы говорите быстрее? Поскольку flex создает AFD для этого регулярного выражения, результат тот же, что и при скорости. Только один проход по данным, так как вы не использовали оператор /. –

+0

@ LuisColorado: Оператор '/' Flex не является особым. Любой шаблон может вызвать (однократное) повторное сканирование, но это может стать квадратичным в расширенном размере шаблона. Рассмотрим, например, ': |: {15}' и вход, состоящий из 14 двоеточий. Каждый двоеточие будет возвращен в качестве односимвольного токена, но только после сканирования до первого двоеточия и последующего отступления. Конечно, это не имеет никакого отношения к использованию чередования; ваш комментарий на 100% правильный, что два регулярных выражения будут скомпилированы с тем же DFA (por sus siglas en inglés). – rici

+0

@ LuisColorado - Я хотел только подчеркнуть, что чередование очень медленное в любом контексте. Написал контрольный показатель, чтобы сравнить эти два. В классическом «развернутом» методе это быстрее на величину 2. – sln

Смежные вопросы