Swift解析.js文件:将JS数组映射到对应Swift数组的最优方案
Great question! Let’s walk through the best way to parse your .js file’s array declarations into strongly-typed Swift arrays, and address whether enumerateSubstrings is the right tool for the job.
Why Not enumerateSubstrings?
First off: enumerateSubstrings is overkill here. That method shines when you need to traverse a string with flexible, unstructured patterns (like custom tokenization or word-by-word processing). But your JS file follows a strict, predictable format (var [varName] = new Array([elements]);), so we can use a more targeted and efficient tool: regular expressions. Regex lets us directly match the entire pattern of each array declaration, extract the variable name and elements in one go, without manual substring traversal.
Step-by-Step Implementation
Here’s a complete, robust solution to parse both integer and string arrays from your JS file:
1. Read the JS File Content
First, load the contents of your .js file into a Swift string:
import Foundation guard let jsFilePath = Bundle.main.path(forResource: "yourFile", ofType: "js"), let jsContent = try? String(contentsOfFile: jsFilePath, encoding: .utf8) else { print("Failed to load or read JS file") return }
2. Parse Arrays with Regex
We’ll use two regex patterns: one for integer arrays, one for string arrays. We’ll extract variable names and elements, then convert them to Swift’s typed arrays.
// Dictionary to store parsed arrays (key: variable name, value: typed Swift array) var parsedArrays: [String: Any] = [:] // MARK: - Parse Integer Arrays let intArrayRegexPattern = #"var (\w+) = new Array\(([\d, ]*)\);"# if let intRegex = try? NSRegularExpression(pattern: intArrayRegexPattern) { let intMatches = intRegex.matches(in: jsContent, range: NSRange(jsContent.startIndex..., in: jsContent)) for match in intMatches { // Extract variable name guard let nameRange = Range(match.range(at: 1), in: jsContent) else { continue } let varName = String(jsContent[nameRange]) // Extract and convert elements to [Int] guard let elementsRange = Range(match.range(at: 2), in: jsContent) else { continue } let elementsString = String(jsContent[elementsRange]) let intArray = elementsString.components(separatedBy: ",") .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } .filter { !$0.isEmpty } // Handle empty elements (e.g., trailing commas) .compactMap { Int($0) } parsedArrays[varName] = intArray } } // MARK: - Parse String Arrays let stringArrayRegexPattern = #"var (\w+) = new Array\(((['"])([^'"]*)\3,?\s*)+\);"# if let stringRegex = try? NSRegularExpression(pattern: stringArrayRegexPattern) { let stringMatches = stringRegex.matches(in: jsContent, range: NSRange(jsContent.startIndex..., in: jsContent)) for match in stringMatches { // Extract variable name guard let nameRange = Range(match.range(at: 1), in: jsContent) else { continue } let varName = String(jsContent[nameRange]) // Extract individual string elements (using a sub-regex) let elementRegexPattern = #"(['"])([^'"]*)\1"# guard let elementRegex = try? NSRegularExpression(pattern: elementRegexPattern) else { continue } let elementMatches = elementRegex.matches(in: jsContent, range: match.range(at: 2)) let stringArray = elementMatches.compactMap { elementMatch in guard let elementRange = Range(elementMatch.range(at: 2), in: jsContent) else { return nil } return String(jsContent[elementRange]) } parsedArrays[varName] = stringArray } } // MARK: - Use the Parsed Arrays // Access your typed arrays like this: if let nameOfVar1 = parsedArrays["nameOfVar1"] as? [Int] { print("Parsed Int array: \(nameOfVar1)") } if let nameOfVar2 = parsedArrays["nameOfVar2"] as? [String] { print("Parsed String array: \(nameOfVar2)") }
Key Notes for Robustness
- Handles whitespace/newlines: The regex and string trimming logic accounts for spaces, tabs, or line breaks in the JS file.
- Trailing commas: The
filter { !$0.isEmpty }line skips empty elements caused by trailing commas in JS arrays. - Single/double quotes: The string array regex works with both
'and"quoted strings. - Empty arrays: The patterns will match empty arrays (e.g.,
var emptyArr = new Array();) and convert them to empty Swift arrays.
Final Verdict
Regex is the optimal approach here—it’s concise, efficient, and tailored to your structured JS format. enumerateSubstrings would require far more manual logic to track variable names, element boundaries, and types, which is unnecessary given the predictable pattern of your input.
内容的提问来源于stack exchange,提问作者Anton

