2013-09-11 3 views
2

Я пытаюсь собрать все регулярные выражения perl, необходимые для проверки базовых типов данных SVG. До сих пор у меня есть:Регулярные выражения Perl для синтаксического анализа основных типов данных SVG

my $w  = "\\s*"; 
my $hexdigit = "[0-9A-Fa-f]"; 
my $c  = "$w,$w"; 
my $i  = "[0-9]+"; 
my $integer = "[+-]?$i"; 
my $p  = "${i}%"; 
my $number = "(?:$integer|[+-]?[0-9]*\.[0-9]+(?:[Ee]$integer)?)"; 
my $angle = "(?:$number$w(?:deg|grad|rad)?)"; 
my $color = "(?:#$hexdigit$hexdigit$hexdigit(?:$hexdigit$hexdigit$hexdigit)?|". 
       "rgb\\($w$i$c$i$c$i$w\\)|". 
       "rgb\\($w$p$c$p$c$p$w\\)|". 
       '(?:'.join("|", sort keys %{svgColours()}). '))'; 
my $length  = "(?:$number(?:em|ex|px|in|cm|mm|pt|pc)?)"; 
my $coordinate = $length; 
my $frequency = "$number(?:Hz|kHz)"; 
my $FuncIRI = "url\(.+\)"; 
my $numberOptionalNumber = "(?:$number|$number$c$number)"; 
my $paint  = "(?:fill|stroke)"; 
my $time  = "(?:$number(?:ms|s))"; 

Пожалуйста, дайте мне знать, если вы видите возможности для улучшения.

+2

Как представляется, нет конкретной проблемы, которую вам необходимо решить, вы можете попросить об этом на http://codereview.stackexchange.com. –

+0

Хорошо - сделаем - спасибо. –

ответ

2

Вы думали о правильной вещи (разбивая материал на композиционную грамматику), но так, как вы это делали, есть проблемы.

Важнейшей проблемой является то, что многие ваши обратные косые черты будут игнорироваться. "url\(.+\)" eq "url(.+)", "... \. ..." не помещает обратную косую черту перед периодом. Чтобы избежать различных правил синтаксического анализа для строк и регулярных выражений, я настоятельно рекомендую использовать котировки регулярных выражений: qr//. Это имеет побочный эффект компиляции все эти регулярные выражений (которые вы на самом деле не хотите), но, по крайней мере, вам не придется делать двойное вытекание:

my $w = qr/\s*/; 
... 
my $paint = qr/fill|stroke/; # enclosing group added automatically 

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

my $color_names = join ... 
my $color = qr/...|...|$color_names/; 

При соединении не-строки регулярных выражений вместе, вы должны как привычка бежать все метасимволы:

join '|', map quotemeta, keys %{ ... }; 

Вместо составления регулярных выражений через переменные интерполяции, вы можете использовать (?(DEFINE) ...):

qr/ 
    (?(DEFINE) 
    (?<ws>  \s*) 
    (?<comma> \s*[,]\s*) 
    (?<integer> [+-]?[0-9]+) 
    (?<percent> (?&integer)[%]) 
    (?<number> (?&integer)(?: [.][0-9]+ (?: [eE](?&integer))?)?) 
    ... 
) 
/x 

Внутри DEFINE среды, вы можете объявить шаблоны, как называли захватами (но они не захватывают, а у ou не может захватить внутри таких шаблонов). Вы можете вызвать такой шаблон, как (?&pattern).

Если вы не хотите просто соответствовать данных, но и проанализировать его, то регулярные выражения могут оказаться непригодными. Я рекомендую парсер Marpa :: R2. Это немного более низкого уровня, и менее выразительный, но имеет хороший BNF синтаксис:

:start ::= NumberList 
:default ::= action => ::array bless => ::lhs 
:discard ~ ws 

NumberList ::= number+ separator => comma 

ws  ~ [\s]+ 
comma ~ ',' 
digits ~ [0-9]+ 
sign ~ [+-] 
integer ~ sign digits | digits 
number ~ integer 
     | integer '.' digits 
     | integer '.' digits [eE] integer 
... 

Прочитайте Marpa documentation, чтобы увидеть, если это libary может быть полезным. В противном случае Parse::RecDescent и Regexp::Grammars являются хорошими альтернативами простым регулярным выражениям. Если вы выберете парсер, основанный на регулярном выражении, вы можете повторно использовать общие шаблоны от Regexp::Common.

+0

(? (DEFINE): спасибо за ваши обширные заметки об этой полезной технике. –

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