2021-03-18

CCF-CSP URL映射

把题目的意思先搞懂。就是给你一些URL规则和一些URL,然后对每个URL,按照先后顺序逐个匹配所有URL规则,按照第一个匹配就匹配的原则。匹配成功则输出规则的名字和所有的参数(就是把参数的值从URL里抠出来);匹配失败则输出404 。

注意处理结尾的斜杠。因为保证以斜杠开头(规则或者ULR都是如此),所以把URL抽象为片段的序列,每个片段前面必有一个斜杠,只需记录整个串是否以斜杠结尾即可。注意题目的规定,如果最后一个片段是path,则不能以斜杠结尾。

最后注意一下规则可能没有片段,即只有一个斜杠的情况,对片段数组要判空。

#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <cctype>
using namespace std;

enum {
	LIT, // 字面值。
	STR, // str
	INT, // int
	PATH, // path
};

const char Name[5][5]={"","str","int","path"};

struct Node {
	int type;
//	如果type是LIT,这里是字面值。 
	string val;
};

struct Rule {
//	路径的各部分。 
	vector<Node> item;
	// 是否以斜杠结尾。必定以斜杠开头。item之间必定隔着斜杠。 
	bool endslash;
	// 规则名。 
	string name;
	Rule() {
		this->endslash=false;
	}
};

int N; // 规则数。 
int M; // 查询数。 

vector<Rule> rules;
#define MAXL 105 // 每行不超过这么多。

int Type(string& s) {
	if (s=="int") {
		return INT;
	}
	if (s=="str") {
		return STR;
	}
	if (s=="path") {
		return PATH;
	}
	return -1;
}

Rule ParseRule(char str[], int len) {
	// 解析路径。
	int i=0;
	Rule r;

	while (i<len) {
		while (i<len && str[i]=='/') {
			++i;
		}
		if (i>=len) {
			break;
		}
		if (str[i] == '<') {
			++i;
			string s;
			while (i<len && str[i]!='>') {
				s.push_back(str[i]);
				++i;
			}
			++i; // '>'
			int type=Type(s);
			Node n;
			n.type=type;
			r.item.push_back(n);
		} else {
			// LIT.
			string s;
			while (i<len && str[i]!='/') {
				s.push_back(str[i]);
				++i;
			}
			Node n;
			n.type=LIT;
			n.val=s;
			r.item.push_back(n);
		}
	}
	// 注意,item可能为空,即只有一个斜杠。 
	if (str[len-1]=='/') {
		r.endslash=(r.item.empty() || r.item.back().type != PATH);
	}
	return r;
}

void PrintRule(Rule& r) {
	for (int i=0;i<r.item.size();++i) {
		putchar('/');
		Node& n=r.item[i];
		switch (n.type) {
			case LIT:
				printf("%s", n.val.c_str());
				break;
			default:
				printf("<%s>", Name[n.type]);
				break;
		}
	}
	if (r.endslash) {
		putchar('/');
	}
	puts("");
}

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

string Clean(string& s) {
	// 返回去掉前导零的数字,如果是全零则返回0. 
	int i=0;
	while (i<s.size()-1 && s[i]=='0') {
		++i;
	}
	return s.substr(i);
}

/*
本题的bug:
有两处地方把==写成=,看来比较运算符两边必须加空格啊。
*/
 
vector<string> params;
bool Match(Rule& r, char str[], int len) {
//	puts(r.name.c_str());
	/*
	扫描规则的所有部分,对每一个部分贪婪匹配输入url。
	如果有一部分不匹配,则false。
	全部匹配完毕后,处理endslash,即规则和url的endslash要一致。
	如果url过长,则false。
	*/
	 
	params.clear();
	int j=0;
	for (int i=0;i<r.item.size();++i) {
		while (j<len && str[j]=='/') {
			++j;
		}
		if (j>=len) {
//			puts("Too short");
			return false;
		}
		Node& n=r.item[i];
		int type=n.type;
		string buf;
		if (type==LIT) {
			while (j<len && str[j]!='/') {
				buf.push_back(str[j]);
				++j;
			}
			if (buf != n.val) {
//				puts("lit false");
//				printf("buf %s val %s\n", buf.c_str(),n.val.c_str());
				return false;
			}
		} else {
			if (type == INT) {
				while (j<len && isdigit(str[j])) {
					buf.push_back(str[j]);
					++j;
				}
				buf=Clean(buf);
			} else if (type == STR) {
				while (j<len && str[j]!='/') {
					buf.push_back(str[j]);
					++j;
				}
			} else {
				// Path
				while (j<len) {
					buf.push_back(str[j]);
					++j;
				}
			}
//			printf("buf %s\n", buf.c_str());
			
			if (buf.empty()) {
//				puts("param false");
				return false; // 不能匹配空字符串。 
			}
			params.push_back(buf);
		}
	}
//	printf("rule end %s endslash %d j %d len %d\n", r.name.c_str(), (int)r.endslash,j,len);
	
	
	if (j==len) {
		return !r.endslash;
	}
	if (j==len-1) {
		bool endslash=(str[j]=='/');
		return endslash==r.endslash;
	}
	return false;
}

int Match2(char str[], int len) {
//	printf("str %s\n", str);
	
	for (int i=0;i<rules.size();++i) {
		if (Match(rules[i], str, len)) {
			return i;
		}
	}
	return -1;
}

int main(int argc, char** argv) {
	scanf("%d%d",&N,&M);
	while (N--) {
		char str[MAXL], name[MAXL];
		scanf("%s%s",str,name);
		Rule r=ParseRule(str, strlen(str));
		r.name=name;
		rules.push_back(r);
	}

	while (M--) {
		char str[MAXL];
		scanf("%s", str);
		int ans=Match2(str, strlen(str));
		if (ans==-1) {
			puts("404");
		} else {
			Rule& r=rules[ans];
			printf("%s", r.name.c_str());
			for (int i=0;i<params.size();++i) {
				printf(" %s", params[i].c_str());
			}
			puts("");
		}
	}
	
#if 0
	puts("");
	for (int i=0;i<rules.size();++i) {
		PrintRule(rules[i]);
	}
#endif

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值