Проблема с регулярным выражением заключается в том, что он не работает с путями длиннее двух элементов.Он разбивает их на db_name и table_name (если есть).Также это регулярное выражение не работает со специальными именами файлов SQLite, такими как ': memory' (которые очень полезны для тестов).
Чтобы иметь поддерживаемый подход RE, лучший способ работать с этим - это иметьтаблица диспетчеризации с основными протоколами, которые требуют различного анализа и имеют подпрограмму для каждого отдельного подхода.Также поможет иметь RE с // x, поэтому он может иметь комментарии и помочь в его поддержке:
sub test_re{
my $url =shift;
my $x={};
@$x{qw(conn driver user pass host port dbname table_name tparam_name tparam_value conn_param_string)} =
$url =~ m{
^(
(\w*)
://
(?:
(\w+) # user
(?:
\:
([^/\@]*) # password
)?
\@
)? # could not have user,pass
(?:
([\w\-\.]+) #host
(?:
\:
(\d+) # port
)? # port optional
)? # host and port optional
/ # become in a third '/' if no user pass host and port
(\w*) # get the db (only until the first '/' is any). Will not work with full paths for sqlite.
)
(?:
/ # if tables
(\w+) # get table
(?:
\? # parameters
(\w+)
=
(\w+)
)? # parameter is conditional but would have always a tablename
)? # conditinal table and parameter
(
(?:
;
(\w+)
=
(\w+)
)* # rest of parameters if any
)
$
}x;
return $x;
}
Но я рекомендую использовать URI :: Split (меньше детализации кода)чем URI ), а затем разделите путь по необходимости.
Здесь вы можете увидеть разницу в использовании RE против URI :: Split:
#!/usr/bin/env perl
use feature ':5.10';
use strict;
use URI::Split qw(uri_join uri_split);
use Data::Dumper;
my $urls = [qw(
mysql://anonymous@my.self.com:1234/dbname
mysql://anonymous@my.self.com:1234/dbname/tablename
mysql://anonymous@my.self.com:1234/dbname/pathextra/tablename
sqlite:///dbname_which_is_a_file
sqlite:///tmp/dbname_which_is_a_file
sqlite:///tmp/db/dbname_which_is_a_file
sqlite:///:dbname_which_is_a_file
sqlite:///:memory
)];
foreach my $url (@$urls) {
print Dumper(test_re($url));
print Dumper(uri_split($url));
}
Результаты:
[...]
== testing sqlite:///dbname_which_is_a_file ==
- RE
$VAR1 = {
'pass' => undef,
'port' => undef,
'dbname' => 'dbname_which_is_a_file',
'host' => undef,
'conn_param_string' => '',
'conn' => 'sqlite:///dbname_which_is_a_file',
'tparam_name' => undef,
'tparam_value' => undef,
'user' => undef,
'table_name' => undef,
'driver' => 'sqlite'
};
- URI::Split
$VAR1 = 'sqlite';
$VAR2 = '';
$VAR3 = '/dbname_which_is_a_file';
$VAR4 = undef;
$VAR5 = undef;
== testing sqlite:///tmp/dbname_which_is_a_file ==
- RE
$VAR1 = {
'pass' => undef,
'port' => undef,
'dbname' => 'tmp',
'host' => undef,
'conn_param_string' => '',
'conn' => 'sqlite:///tmp',
'tparam_name' => undef,
'tparam_value' => undef,
'user' => undef,
'table_name' => 'dbname_which_is_a_file',
'driver' => 'sqlite'
};
- URI::Split
$VAR1 = 'sqlite';
$VAR2 = '';
$VAR3 = '/tmp/dbname_which_is_a_file';
$VAR4 = undef;
$VAR5 = undef;
== testing sqlite:///tmp/db/dbname_which_is_a_file ==
- RE
$VAR1 = {
'pass' => undef,
'port' => undef,
'dbname' => undef,
'host' => undef,
'conn_param_string' => undef,
'conn' => undef,
'tparam_name' => undef,
'tparam_value' => undef,
'user' => undef,
'table_name' => undef,
'driver' => undef
};
- URI::Split
$VAR1 = 'sqlite';
$VAR2 = '';
$VAR3 = '/tmp/db/dbname_which_is_a_file';
$VAR4 = undef;
$VAR5 = undef;
== testing sqlite:///:memory ==
- RE
$VAR1 = {
'pass' => undef,
'port' => undef,
'dbname' => undef,
'host' => undef,
'conn_param_string' => undef,
'conn' => undef,
'tparam_name' => undef,
'tparam_value' => undef,
'user' => undef,
'table_name' => undef,
'driver' => undef
};
- URI::Split
$VAR1 = 'sqlite';
$VAR2 = '';
$VAR3 = '/:memory';
$VAR4 = undef;
$VAR5 = undef;