背景
学习 Swift 三方库源代码的时候,Xcode 里面的目录结构,与实际工程的文件结构不一致
调试不方便
-
一般 Xcode 里面看到的代码文件,是有层次的。文件夹里面的代码,都在一层,不好找
-
Xcode 里面看到的代码文件,一个文件夹下面的太多了,不够细致
根据代码里面的文件结构,创建相应的文件夹,把代码文件移入,好一些
有一点强迫症的感觉
本文完成第一步,文本解析
案例:
学习 AudioKit/AudioKit 有一个库 AudioKit/Cookbook,
本文整理他的代码
效果:
从这样
Form {
Section(header: Text("Mini Apps")
.padding(.top, 20)) {
Section {
NavigationLink(destination: DrumsView()) { Text("Drum Pads") }
NavigationLink(destination: DrumSequencerView()) { Text("Drum Sequencer") }
NavigationLink(destination: DrumSynthesizersView()) { Text("Drum Synthesizers") }
NavigationLink(destination: GraphicEqualizerView()) { Text("Graphic Equalizer") }
NavigationLink(destination: MusicToyView()) { Text("Music Toy") }
/...
到这样:
0_0 : ["DrumsView", "DrumSequencerView", "DrumSynthesizersView",
"GraphicEqualizerView", "MusicToyView", "Telephone", "TunerView",
"NoiseGeneratorsView", "VocalTractView", "MIDIMonitorView"]
// ...
解决:
思路:
把所有文件的类名,按照顺序找出来,用正则表达式简单
按照顺序找出所有的类名,建立层级,稍微麻烦
正则处理
本文的案例中,有嵌套代码,即有层级
例子中的 Section
,最多两层嵌套
先把最外层的 Section
中的代码,索引分块,
之后正则出条目,完
代码:
正则表达式,不好处理嵌套的内容,
嵌套的内容,一般使用递归,
案例中清楚其层级,两层 while 循环就好
第一步,去除无效符号
本文采用命令行程序,
加载文件
if let src = URL(string: "\(NSHomeDirectory())/Documents/Lalathon/src/ContentView.swift"){
do {
contents = try String(contentsOfFile: src.path)
// print(contents ?? "")
} catch {
print(error)
}
}
去除空格和换行
// 去除空格和换行
guard let info = contents?.replacingOccurrences(of: " ", with: "").replacingOccurrences(of: "\n", with: "") else{
fatalError()
}
第 2 步,去除最外层的 section
采用的是字符串遍历,
首先碰到 “Section”, 遇到 “{”, 开始看 bracketCount 的值,
之后进入嵌套的 while 循环,
遇到 “{” , bracketCount + 1,
遇到 “}” , bracketCount - 1
当 bracketCount == 0, 就处理完了一个 最外层的 “Section”
struct TargetInfo{
let start = "Section"
let second: Character = "{"
let end: Character = "}"
}
let target = TargetInfo()
func extract(content info: String) -> [String]{
var i = 0
let total = info.count
var result = [String]()
while i < total {
let endIndex = i + target.start.count - 1
if endIndex >= total{
break
}
if let temp = info[i...endIndex], temp == target.start{
var bracketCount = 0
i += target.start.count - 1
var beginIndex = 0
first: while i < total {
inner: switch info[i] {
case target.second:
if bracketCount == 0{
beginIndex = i
}
bracketCount += 1
case target.end:
bracketCount -= 1
if bracketCount == 0{
result.append(info[(beginIndex+1)...(i-1)] ?? "")
break inner
}
default:
()
}
i += 1
}
}
i += 1
}
return result
}
第 3 步,整理第一层数据
之后,就是不断的 map, filter
先过滤,只取需要的数据,
这里用的关键词是 “NavigationLink”, 用其他的当然可以
var rawInfo = extract(content: info)
// filter
rawInfo = rawInfo.filter { (piece) -> Bool in
piece.contains("NavigationLink")
}
整理第一层的数据
采用二维数组,
element[0]
第一个元素,文件夹初步编号
element[1]
第二个元素,内容
var i = 0
let cnt = rawInfo.count
// midData
// 0, content zero
// 1, content one
var midData = [[String]]()
while i < cnt{
midData.append(["\(i)", rawInfo[i]])
i += 1
}
第 4 步,整理第 2 层数据
总共就两层,就是整理里层的数据
先判断,包含 “Section”,就是存在第二层
不包含 “Section”,直接添加
// handledData
// 0_0, content zero zero
// 0_1, content zero one
// 1, content one
var handledData = [[String]]()
print("-------")
for piece in midData{
if piece[1].contains(target.start){
let list = extract(content: piece[1])
// list.debug()
let temp = list.enumerated().map({ (tmp) -> [String] in
["\(piece[0])_\(tmp.offset)", tmp.element]
})
// temp.debug()
handledData.append(contentsOf: temp)
}
else{
handledData.append(piece)
}
}
最后,完成文本解析,建立索引
还是二维数组,
element[0]
第 1 个元素,文件夹名称
element[1...]
剩余的元素,对应的类名列表
var result = [[String]]()
// index, file list
for piece in handledData{
if let list = regex(with: piece[1]){
// list.debug()
let tmp = [piece[0]] + list
result.append(tmp)
}
}
还需要做的,根据类名找文件名,
建立文件夹,移动相应的文件进去