Я нашел регулярное выражение анализатора URL в RFC 2396 и RFC 3986.
^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
Я преобразовал его в Ragel:
%%{
# RFC 3986 URI Generic Syntax (January 2005)
machine url_parser;
action pchar {
printf("%c", fc);
}
action scheme { printf("scheme\n"); }
action scheme_end { printf("\nscheme_end\n"); }
action authority { printf("authority\n"); }
action authority_end { printf("\nauthority_end\n"); }
action path { printf("path\n"); }
action path_end { printf("\npath_end\n"); }
action query { printf("query\n"); }
action query_end { printf("\nquery_end\n"); }
action fragment { printf("fragment\n"); }
action fragment_end { printf("\nfragment_end\n"); }
scheme = (any - [:/?#])+ >scheme $pchar %scheme_end ;
authority = (any - [/?#])* >authority $pchar %authority_end ;
path = (any - [?#])* >path $pchar %path_end ;
query = (any - [#])* >query $pchar %query_end ;
fragment = (any)* >fragment $pchar %fragment_end ;
main := (( scheme ":" )?) <: (( "//" authority )?) <: path ( "?" query )? ( "#" fragment )?;
}%%
#include <cstdio>
#include <cstdlib>
#include <string>
/** Data **/
%% write data;
int main(int argc, char **argv) {
std::string str(argv[1]);
char const* p = str.c_str();
char const* pe = p + str.size();
char const* eof = pe;
int cs = 0;
%% write init;
%% write exec;
return p - str.c_str();
}
Это работает, когда я вводю абсолютный URI.
liangxu@dev64:~$ ./uri_test "http://www.ics.uci.edu/pub/ietf/uri/?c=www&rot=1&e=%20%20"
scheme
http
scheme_end
authority
www.ics.uci.edu
authority_end
path
/pub/ietf/uri/
path_end
query
c=www&rot=1&e=%20%20
query_end
И успех при вводе полномочий и пути:
liangxu@dev64:~$ ./uri_test "//www.ics.uci.edu/pub/ietf/uri/?c=www&rot=1&e=%20%20"
authority
www.ics.uci.edu
authority_end
path
/pub/ietf/uri/
path_end
query
c=www&rot=1&e=%20%20
query_end
Но сбой при вводе только пути:
liangxu@dev64:~$ ./uri_test "/pub/ietf/uri"
Что не так?