作者:东方教主
链接:https://juejin.cn/post/6910243717450465288

背景

学习 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()
}

这里有一个iOS交流圈:891 488 181 可以来了解,分享BAT,阿里面试题、面试经验,讨论技术,裙里资料直接下载就行, 大家一起交流学习!想要学习的就来,不想的..........那就算了吧,反正白嫖的你都不要。
第 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)
    }

}

还需要做的,根据类名找文件名,

建立文件夹,移动相应的文件进去
文章到这里就结束了,你也可以私信我及时获取最新资料以及面试相关资料。如果你有什么意见和建议欢迎给我留言。