我正在尝试收集验证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))";
如果您有机会改进,请告诉我。
答案 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::RecDescent和Regexp::Grammars是普通正则表达式的良好替代品。如果选择基于正则表达式的解析器,则可以重用Regexp::Common中的常用模式。