题目链接: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);
}
}