題目連結: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);
}
}