Preface:
You can do it in three steps,
-
Text parsing, extracting information
-
Sort out the hierarchy of dependency diagrams
-
Draw out
This is an introduction to functional programming to parse and extract information
Functional Programming and Text parsing, Review Octree/Pretty
This article introduces the process oriented, using regular expressions, parsing text,
The second step is to sort out the dependency map
Any reference octree/pretty
The first step, text parsing, extract information
Process oriented, friendly, clear, not so much functional paradigm
Less code than functions
Maybe, in pretty, functional programming, need to improve
From the text, get the dictionary [parent lib: [child lib]]
struct Parser { func parse(_ content: String) -> [String: [String]]? Struct Tag{struct pageStart = "PODS:\n" // let lineEnd: Character = "\n" // let pageEnd: String // Parent lib let itemStart = String(repeating: "", count: 2) " ", count: 4) init() { pageEnd = String(repeating: "\(lineEnd)", count: 2) } } let tag = Tag() guard content.hasPrefix(tag.pageStart) else { return nil } let info = content.rm(header: tag.pageStart) guard let temp = info.components(separatedBy: tag.pageEnd).first else{ return nil } var result = [String: [String]]() let list = temp.split(separator: Tag. LineEnd) // Add the message, Var keys = "" var vals = [String]() var started = false for item in list{let TMP = String(item) if Tmp.hasprefix (tag.subitemStart){// Sublib vals. Append (tmp.rm(header: tag.subItemStart).rmRegexHeader.regexExtract) } else if tmp.hasPrefix(tag.itemStart){ if started{ result[key] = vals } // Parent lib vals. RemoveAll () started = true key = tmp.rm(header: tag.itemStart).rmRegexHeader.regexExtract } } if result.isEmpty{ return nil } else{ return result } } }Copy the code
Helper method
Func rm(header STR: String) -> String{return String(dropFirst(str.count))} String{ if let tmp = match(regex: #"- "?" #){return String(dropFirst(tmp.count))} else{return self}} String{ if let tmp = match(regex: #"[^\s]+"#){ return tmp } else{ return self } } func match(regex: String) -> String? { guard let regex = try? NSRegularExpression(pattern: regex) else { return nil } let results = regex.matches(in: self, range: NSRange(location: 0, length: utf8.count)) let nsString = self as NSString if let first = results.first{ return nsString.substring(with: first.range) } else{ return nil } } }Copy the code
To optimize the
The following paragraph, which is not very logical,
In the for loop, the logic for the child module is processed first, and then the logic for the parent lib
var result = [String: [String]]() let list = temp.split(separator: Tag. LineEnd) // Add the message, Var keys = "" var vals = [String]() var started = false for item in list{let TMP = String(item) if Tmp.hasprefix (tag.subitemStart){// Sublib vals. Append (tmp.rm(header: tag.subItemStart).rmRegexHeader.regexExtract) } else if tmp.hasPrefix(tag.itemStart){ if started{ result[key] = vals } / lib/father vals. RemoveAll () started = true key = TMP. The rm (header: tag. ItemStart). RmRegexHeader. RegexExtract}}Copy the code
Can be adjusted to process the parent lib first, then the child lib, consistent with the actual data logic
var result = [String: [String]]() let list = temp.split(separator: tag.lineEnd) let cnt = list.count var i = 0 while i < cnt { var tmp = String(list[i]) var key: String? Var vals = [String]() lib if tmp.isitem {key = tmp.rm(header: Tag. ItemStart). Word I += 1} i < cnt { tmp = String(list[i]) if tmp.isSubitem{ vals.append(tmp.rm(header: tag.subItemStart).word) i += 1 } else{ stay = false } } if let k = key{ result[k] = vals } else{ return nil } }Copy the code
Helper method
extension String{
var isItem: Bool{
let tag = Tag()
return hasPrefix(tag.itemStart) && (hasPrefix(tag.subItemStart) == false)
}
var isSubitem: Bool{
let tag = Tag()
return hasPrefix(tag.subItemStart)
}
var word: String{
rmRegexHeader.regexExtract
}
}
Copy the code
Step 2, sort out the hierarchy of the dependency graph
From dictionary [parent lib: [child lib]]
Get the auxiliary dictionary, [child lib: [parent lib]]
private func parentNode(_ dependency: [String: [String]]) -> [String: [String]] { var pMap = [String: [String]]() for (key, sons) in dependency { for name in sons { var parents = pMap[name] ?? [] parents.append(key) pMap[name] = parents // pMap[name] = key // return pMap}Copy the code
[Top libs info, Seccond Libs Info,…]
Take out the top lib that doesn’t have a parent,
Then from the rest of the lib, pull out the lib that does not have a parent, and repeat
Func groupPodDependency(_ dependency: [String: [String]]) -> [[String: [String]] {let reversed = parentNode(dependency) // Same as Set(dependency. Keys) Var names = Set(dependency. Keys) var lastDepthNames = [String]() var groups = [[String: [String]]]() while names.count > 0 { var group = [String: [String]]() let copyedNames = names // copyedNames, first round, is for each lib // later round, is the rest of which, Each lib for name in copyedNames {// first round, lastDepthNames [] // For top lib without parent lib, // reversed[name] = [] if lastDepthNames.contains(reversed[name] ?? Group [name] = dependency[name]}} lastdepthnames. append(contentsOf: group.keys) groups.append(group) } return groups }Copy the code
Draw out
[[String: [String]]]
Each element [String: [String]] is the information for each layer
[String: [String]], the key is a layer of lib,
The values corresponding to key are the connection between the lib and its sub-lib
- To draw it, see Github Repo