处理include标签其实第一章的习题部分,因为篇幅过大所有决定单独开一章节。
题目要求如下:
既然第一章学了递归,那我们不妨也用递归的方式来处理解决。
大体逻辑其实很简单,就是逐行读文件内容,遇到#include标签则递归处理被引入的文件名。
核心代码如下。
/**
* Process file's include recursively.
* @return file content with included file's content.
*/
private fun processFile(filename: String): String {
// If file is invalid, that is not in valid files.
if(filename !in INVALID_FILES) {
throw IllegalArgumentException("file not valid with name $filename")
}
// If file not exists, print error message and throw an exception.
val file = File(FILE_DIRECTORY, filename)
if(!file.exists()) {
throw FileNotFoundException("file not foud with path $file")
}
// Read file content and process referenced file if needed.
val fileReader = BufferedReader(InputStreamReader(file.inputStream(), StandardCharsets.UTF_8))
val fileContent = StringBuilder()
while (true) {
val line = fileReader.readLine() ?: break
// Hit include keyword!!!
if(line.matches(KEYWORD_REGEX.toRegex())) {
// Get filename after the include.
val includeFileName = getFileName(line)
// File is not self-referential.
if(includeFileName.isNotEmpty() && includeFileName != filename) {
fileContent.append(processFile(includeFileName)).append("\n")
}
} else {
fileContent.append(line).append("\n")
}
}
// Simply close
fileReader.close()
return fileContent.toString()
}
最后我们建4个文件来演示下,其中四个文件的引用关系如下:
随便加些内容,可以看到,结果已经正常显示 :
其中file2引用自身无效,在代码中已处理。
当然了,在实际应用中不应该用递归来实现,因为每次递归都打开了一个文件流,如果递归的深度很大,是非常消耗性能的。