我正在尝试收集验证 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))";
如果您发现改进的机会,请告诉我。
最佳答案
您的想法是正确的(将内容拆分为可组合语法),但您这样做的方式有问题。
最重要的问题是许多反斜杠将被忽略。 "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中的常见模式。 .
关于regex - Perl正则表达式解析SVG基本数据类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18743629/