I want to check a string by using multiple search patterns and split the string at every occurrence. I'm using RegEx and it works fine. But I'm worrying about efficiency and performance.
struct StringPart {
let text : String
var matched : Int // index of pattern
let pos : Int
init(searchText: String, matched : Int, firstIndex : Int) {
self.text = searchText
self.matched = matched
self.pos = firstIndex
}
}
extension StringPart {
func toString() -> String {
return text
}
}
func SplitNumsArray(searchString : String, patterns : [String]) -> [StringPart] {
var results = [StringPart]()
var index = 0
// init with first string
results.append(StringPart(searchText: searchString, matched: -1, firstIndex: 0))
index += searchString.characters.count
var patternIndex = 0
for pattern in patterns {
var resultIndex = 0
for result in results {
if result.matched == -1 {
let res1Run = SplitNums(searchText : result.text, pattern : pattern, patternIndex: patternIndex)
results.remove(at: resultIndex)
results.insert(contentsOf: res1Run, at: resultIndex)
resultIndex += res1Run.count - 1
}
resultIndex += 1
}
patternIndex += 1
}
return results
}
func SplitNums(searchText : String, pattern : String, patternIndex : Int = 0) -> [StringPart] {
var results = [StringPart]()
var index = 0
var s = searchText
results.append(StringPart(searchText: s, matched: -1, firstIndex: index))
index += s.characters.count
let regex = try! NSRegularExpression(pattern: pattern, options: [])
// initial search
var matches = regex.matches(in: s, options: [], range: NSRange(location: 0, length: s.characters.count))
while matches.count > 0 {
// we only need the first one!
let match = matches[0]
if match.numberOfRanges > 0 {
let range = match.rangeAt(0)
let beforeRange = s.startIndex..<s.characters.index(s.startIndex, offsetBy: range.location)
let foundRange = s.characters.index(s.startIndex, offsetBy: range.location)..<s.characters.index(s.startIndex, offsetBy: range.location+range.length)
let endRange = s.characters.index(s.startIndex, offsetBy: range.location+range.length)..<s.endIndex
let foundString = s.substring(with: foundRange)
let beforeString = s.substring(with: beforeRange)
let endString = s.substring(with: endRange)
// remove last part, because it will be replaced by new split
let lastIndex = results.count - 1
results.remove(at: lastIndex)
if beforeString.characters.count > 0 {
results.append(StringPart(searchText: beforeString, matched: -1, firstIndex: index))
index += beforeString.characters.count
}
if foundString.characters.count > 0 {
results.append(StringPart(searchText: foundString, matched: patternIndex, firstIndex: index))
index += foundString.characters.count
}
if endString.characters.count > 0 {
results.append(StringPart(searchText: endString, matched: -1, firstIndex: index))
index += endString.characters.count
}
s = endString // last part can be reused for next search
}
// read again!
matches = regex.matches(in: s, options: [], range: NSRange(location: 0, length: s.characters.count))
}
return results
}
There are two functions: one handles one pattern string, and the other one is calling the first one repeatedly. But in one call I get several matching information. I drop it and use the remaining string again for the next matching. This works fine, but I redo something, which was already done.
Some examples:
let numberPatterns = [ "\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}_.*_",
"\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}_.*$",
"\\d{4}\\.\\d{2}\\.\\d{2}-\\d{2}\\.\\d{2}\\.\\d{2}$",
"\\d{7}", "\\d{6}", "\\d{5}", "\\d{4}" ]
example strings:
IMG_1234_5678
2010.10.03 Feiertag
IMG_12345_2015.10.04-17.45.30_Test
IMG_12345_12346_12347