天天看點

CCF201509-3 模闆生成系統

題目連結:http://115.28.138.223/view.page?gpid=T30

題目為字元串處理,欲将模闆中的字元串替換為指定語句,類似于c語言中的#define的實作,但題目中要特别注意一點,模闆不遞歸生成,“也就是說,如果變量的值中包含形如 {{ VAR }} 的内容,不再做進一步的替換”。

若是逐字元處理,則無需考慮遞歸的問題,可以解決問題。

使用正規表達式可以比較友善的解決這個問題,但是需要注意避免遞歸生成模闆。

可以在原文中找到所有需要替換的内容,前面加字首Y。在所有變量前面加字首Y,在題目給的變量内容中可以在被比對到的内容上加字首N來避免遞歸,最後隻需删除字首即可。

即原文中所有的{{ VAR }}變為{{ YVAR }},變量的值中的就變為{{ NVAR }}(好像和部分c++編譯器識别重載函數類似吧)

靈活運用正規表達式中的文法回溯引用來簡化文法,需要注意的是,回溯引用在各個程式設計語言中有不同的寫法,java中$1比對第一個括号,以此類推。

這個程式可以得到90分,有些不足。代碼是用java實作的,另外c++中也有regex庫可以使用。

JAVA語言代碼

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

public class Main {

	public static void main(String[] args) {
		// TODO 自動生成的方法存根
		HashMap<String, String> keys = new HashMap<>();//name-value
		String text="";//檔案内容
		int textnum,keysnum;//檔案行數,變量數
		/*input*/
		Scanner scanner = new Scanner(System.in);
		textnum = scanner.nextInt();
		keysnum = scanner.nextInt();
		scanner.nextLine();
		for(int i=0;i<textnum;i++){
			text+=(scanner.nextLine()).replaceAll("\\{\\{ ([_a-zA-Z0-9]+) \\}\\}", "\\{\\{ Y_$1 \\}\\}")+"\n";//防止遞歸,加字首Y_,回溯引用
		}

		Pattern name = Pattern.compile("^[_a-zA-Z0-9]+(?=\\s)");//擷取變量名字
		Pattern context = Pattern.compile("(?<= \").+(?=\")");//擷取變量内容
		for(int i=0;i<keysnum;i++){
			String temp,tname,ttext;
			temp = scanner.nextLine();

			Matcher matcher = name.matcher(temp);
			if(matcher.find()){
				tname = matcher.group();
				matcher = context.matcher(temp);
				if(matcher.find()){
					ttext = matcher.group();
				}else {
					ttext = "";
				}
				keys.put("Y_"+tname, ttext.replaceAll("\\{\\{ ([_a-zA-Z0-9]+) \\}\\}", "\\{\\{ N_$1 \\}\\}"));//防止遞歸,回溯引用,加字首N_
			}
		}
		//System.out.println(keys);
		Pattern pName = Pattern.compile("(?<=\\{\\{ )Y_[_a-zA-Z0-9]+(?= \\}\\})");//擷取文中的變量名字
		Matcher matcher = pName.matcher(text);
		while(matcher.find()){
			text = text.replaceAll("\\{\\{ "+matcher.group()+" \\}\\}", keys.containsKey(matcher.group())?keys.get(matcher.group()):"");
		}
		text = text.replaceAll("\\{\\{ N_([_a-zA-Z0-9]+) \\}\\}", "{{ $1 }}");//回溯引用删除字首
		System.out.println(text);
	}

}