Perl正则表达式来解析SVG基本数据类型

时间:2013-09-11 14:14:17

标签: regex perl svg

我正在尝试收集验证SVG基本数据类型所需的所有perl正则表达式。到目前为止,我有:

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))";

如果您有机会改进,请告诉我。

1 个答案:

答案 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环境中,您可以将模式声明为命名捕获(但它们无法捕获,您无法在此类模式中捕获)。您可以调用(?&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以查看此图书馆是否有用。否则,Parse::RecDescentRegexp::Grammars是普通正则表达式的良好替代品。如果选择基于正则表达式的解析器,则可以重用Regexp::Common中的常用模式。