试题编号: | 201803-3 |
试题名称: | URL映射 |
时间限制: | 1.0s |
内存限制: | 256.0MB |
问题描述: | 问题描述 URL 映射是诸如 Django、Ruby on Rails 等网页框架 (web frameworks) 的一个重要组件。对于从浏览器发来的 HTTP 请求,URL 映射模块会解析请求中的 URL 地址,并将其分派给相应的处理代码。现在,请你来实现一个简单的 URL 映射功能。 输入格式 输入第一行是两个正整数 n 和 m,分别表示 URL 映射的规则条数和待处理的 URL 地址个数,中间用一个空格字符分隔。 输出格式 输入共 m 行,第 i 行表示 qi 的匹配结果。如果匹配成功,设匹配了规则 pj ,则输出对应的 rj。同时,如果规则中有参数,则在同一行内依次输出匹配后的参数。注意整数参数输出时要把前导零去掉。相邻两项之间用一个空格字符分隔。如果匹配失败,则输出 404。 样例输入 5 4 样例输出 year_archive 2004 样例说明 对于第 1 个地址 /articles/2004/,无法匹配第 1 条规则,可以匹配第 2 条规则,参数为 2004。 数据规模和约定 1 ≤ n ≤ 100,1 ≤ m ≤ 100。 |
版本一(时间:2018.07.25)
问题链接:CCF201803-3 URL映射
问题分析:大模拟题,有一个细节,就是要注意判断URL规则和地址的最后面是否有 “/”
程序说明:C++程序没有使用正则表达式,纯粹按照题意进行处理。程序使用了vector和串的一些操作,在文本处理过程中使用vector有利于编程者把重心放在文本处理上,而不是过多地考虑存储细节。
提交后得100分的C++程序:
#include<iostream>
#include<vector>
#include<string>
#include<cstring>
#include<ctype.h>
using namespace std;
bool legal(char *s)
{
for(int i=0;i<strlen(s);i++)//如果不是合法的 URL地址返回false
if(s[i]!='/'&&s[i]!='.'&&s[i]!='-'&&s[i]!='_'&&!(isalpha(s[i])||isdigit(s[i])))
return false;
return true;
}
bool int_right(string s) //判断一个字符串是全为数字
{
for(int i=0;i<s.length();i++)
if(!isdigit(s[i]))
return false;
return true;
}
struct Rule{ //规则
vector<string>rule;//存储规则
string name;//匹配的名字
bool flag;//规则结尾是否有 / ,有则为true否则为flase
}r[105];
vector<string>url;//存储输入的url路径
vector<string>para;//存储参数
int n; //规则的个数
void init() //初始化把规则和匹配名存储在向量中
{
string tmp;
char a[110];//临时字符数组
int pos=0;
for(int i=1;i<=n;i++){
scanf("%s",a);//读入url规则
int end=strlen(a);
if(end>0&&a[end-1]=='/')
r[pos].flag=true;
else
r[pos].flag=false;
cin>>r[pos].name;//读入url匹配名
char *sp=strtok(a,"/");//以斜杠分割字符串
while(sp){
r[pos].rule.push_back(sp);
sp=strtok(NULL,"/");
}
pos++;
}
}
bool postfix;//输入的URL地址的后缀是否有 /
void match(char *a) //判断url地址(字符数组a存储的)是否匹配已有的规则
{
url.clear();//清空存储url的向量
char *sp=strtok(a,"/");//以斜杠分割字符串,并存储在url向量中
while(sp){
url.push_back(sp);
sp=strtok(NULL,"/");
}
//匹配
for(int i=0;i<n;i++){//匹配现有的 n 条规则
int j,k;//k表示url的段编号
para.clear();//清空存储参数的向量
bool flag=true;
for(j=0,k=0;j<r[i].rule.size()&&k<url.size();j++,k++){//每条规则被分割成了r[i].rule.size()段
string s=r[i].rule[j];
//情况一
if(s=="<int>"){
if(!int_right(url[k])){//如果它不是数字串的话,匹配失败
flag=false;
break;
}
else{//去掉前导0
string str=url[k];
int t;
for(t=0;t<str.length()-1&&str[t]=='0';t++);
str=str.substr(t);
if(str!="")
para.push_back(str);
}
}
//情况二
else if(s=="<str>")
para.push_back(url[k]);
//情况三
else if(s=="<path>"){
string tmp=url[k++];
for(;k<url.size();k++)
tmp=tmp+"/"+url[k];
if(postfix)
tmp+="/";
para.push_back(tmp);
}
//情况四
else{
if(s!=url[k]){
flag=false;
break;
}
}
}
if(flag&&j>=r[i].rule.size()&&k>=url.size()&&r[i].flag==postfix){
cout<<r[i].name;
for(int ii=0;ii<para.size();ii++)
cout<<" "<<para[ii];
cout<<endl;
return;
}
}
cout<<"404"<<endl;
}
int main()
{
int m;
string s;
cin>>n>>m;
init();//初始化存储n条url规则
while(m--){
char a[110];//临时字符数组
scanf("%s",&a);//读入url地址
int end=strlen(a);
if(end>0&&a[end-1]=='/')
postfix=true;
else
postfix=false;
if(!legal(a)){//如果不是合法的url地址
cout<<"404"<<endl;
continue;
}
match(a);
}
return 0;
}
版本二(时间:2019.03.07)
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
const int N=105;
struct Rule{
vector<string>p;//URL匹配的规则
string r;//URL 匹配的名字
bool flag;//标记规则最后是否有"/"
}a[N];
//字符串分割函数,将字符串s用"/"分割,并存放于向量v中
void split(vector<string> &v,char *s)
{
char *sp=strtok(s,"/");
while(sp)
{
v.push_back(sp);
sp=strtok(NULL,"/");
}
}
//判断字符串s是否都是数字
bool isNum(string s)
{
for(int i=0;i<s.length();i++)
if(!isdigit(s[i]))
return false;
return true;
}
int n,m;//规则和查询的条数
//处理URL地址,flag标记此URL地址最后是否有"/"
void solve(vector<string>URL,bool flag)
{
int i;
vector<string>ans;//存放参数
for(i=0;i<n;i++)//顺序遍历n条规则
{
ans.clear();//先清空
int j=0,k=0;
vector<string>t(a[i].p);
while(j<t.size()&&k<URL.size())//查看URL是否和此规则匹配
{
if(t[j]=="<int>")//情况一:<int>
{
if(isNum(URL[k]))//如果都是数字
{
int w;
for(w=0;w<URL[k].size()-1&&URL[k][w]=='0';w++);//去前导零
ans.push_back(URL[k].substr(w));
j++,k++;//匹配下一部分
continue;
}
}
else if(t[j]=="<str>")//情况二:<str>
{
ans.push_back(URL[k]);//直接记录即可
j++,k++;//匹配下一部分
continue;
}
else if(t[j]=="<path>")//情况三: <path>
{
string s;
while(k<URL.size()) s=s+"/"+URL[k++];
ans.push_back(s.substr(1));//要去除第一个"/"符号
j++;
continue;
}
else if(t[j]==URL[k])
{
j++,k++;//匹配下一部分
continue;
}
break;
}
if(j==t.size()&&k==URL.size()&&flag==a[i].flag) break;//如果匹配就跳出
}
if(i==n)
cout<<"404"<<endl;//如果n条规则都匹配失败,则输出"404"
else
{
cout<<a[i].r;//输出匹配的规则的名字
for(int w=0;w<ans.size();w++)//输出各个参数
cout<<" "<<ans[w];
cout<<endl;
}
}
int main()
{
cin>>n>>m;
string rule;
for(int i=0;i<n;i++)
{
char temp[120];
scanf("%s",temp);
cin>>a[i].r;
a[i].flag=(temp[strlen(temp)-1]=='/')?true:false;//记录规则的最后是否有"/"
split(a[i].p,temp);//分割
}
for(int i=0;i<m;i++)
{
vector<string>URL;
char temp[120];
scanf("%s",temp);
bool flag=(temp[strlen(temp)-1]=='/')?true:false;//记录规则的最后是否有"/"
split(URL,temp);//分割
solve(URL,flag);//判断处理
}
return 0;
}