1. 程式人生 > >CCF URL對映 java 100分詳解 :巧妙地動態構造正則表示式

CCF URL對映 java 100分詳解 :巧妙地動態構造正則表示式

 主要想法:將<int>替換成([0-9]+),將<str>替換成([^/]+),將<path>替換成(.+),

例如,/articles/<int>/<int>/<str>/ 替換之後就會變成/articles/([0-9]+)/([^/]+)/(.+)/ ,這樣它就成了一個正則表示式,可以完全匹配到/articles/1985/09/aloha/,並且利用小括號的分組功能可以將其中的引數提取出來

但這樣有一個麻煩,這個討厭的麻煩就是整數引數要去除前導0,要注意,如果對應的是<str>或<path>則不能去除,

所以麻煩就在於要判斷它對應的是不是<int>,因此這一步我用了大量程式碼繁瑣的步驟來判斷。

import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
Scanner scan=new Scanner(System.in);
	
	int m=scan.nextInt();
	int n=scan.nextInt();
	scan.nextLine();
	String[] input=new String[m];//儲存原有的規則內容以便前導0判斷<int>
	String[][] rules=new String[m][2];這個陣列第一個元素存的是構造後的正則,第二個是規則名
	for(int i=0;i<m;i++) {
		input[i]=scan.nextLine();
		rules[i] =input[i].split(" ");//按空格將規則分兩半
		rules[i][0]=rules[i][0].replaceAll("<int>", "([0-9]+)").replaceAll("<str>","([^/]+)").replaceAll("<path>","(.+)");
	}//將規則變成正則表示式
	String[] output=new String[n];
	for(int i=0;i<n;i++) {
		String url=scan.nextLine();
		if(!url.matches("[/A-Za-z0-9\\-\\._]+")) {//判斷輸入是否合法
			output[i]="404";
			continue;
		}
		boolean flag=false;//標記是否已經匹配到了
	
		for(int j=0;j<m;j++) {//遍歷每一項規則
			String[] rule = rules[j];
			Pattern p=Pattern.compile(rule[0]);
			Matcher matcher=p.matcher(url);
			if(matcher.matches()) {//如果完全匹配,注意區別:find()是部分匹配
				flag=true;
				output[i]=rule[1];//先存入規則名
				for(int k=1;k<=matcher.groupCount();k++) {//逐一獲取引數值
					String param=matcher.group(k);//對每個引數值,判斷它是否以0開頭,如果不是,就直接接到輸出後面,如果是,則要判斷它對應的引數型別是否為<int>
					if(!param.startsWith("0"))//如果是<str>或<path>怎麼辦
					  output[i]=output[i]+" "+param;
					else {//找出該條規則中的所有引數佔位符,就是形如<xxx>的
						Pattern pp=Pattern.compile("(<[a-z]+>)");
						Matcher mat=pp.matcher(input[j]);
						int count=0;
						while(mat.find()) {
							 count++;//找到第K個佔位符,因為這個引數值是第k個,所以對應的是該條規則中的第k個引數,也就是第k個<xxx>
							 if(count==k) break;
						}
						if(mat.group(1).equals("<int>"))
							param=param.substring(1);
						output[i]=output[i]+" "+param;
						
					}//else startsWith("0")
				}//for groupCount
				
			break;	//既然找到了第一個完全匹配的規則,搞完了就跳出
			}//if matches
		
		}//for j:m
		if(flag==false) output[i]="404";//遍歷了所有規則也沒找到匹配的
	}//for i:n
	
	for(String s:output) System.out.println(s);
	
	}

}