import Foundation
let pattern = #"\(+\*+(?:(?:\(+\*+(?:(?:\(+\*+(?:[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+)|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+)|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+"#
let regex = try! NSRegularExpression(pattern: pattern)
let testString = ##"""
The following regex handles any (* *) style string. Let's call it p{1}
p{1} = \(+\*+(?:[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
The targeted string can include the characters {*, (, )}, but not the character sequences "(*" or "*)" (on which the regex terminates).
Examples:
(* simple one *)
(* more * ) ( * () **( difficult * ))()*(( one *)
(* r *( e*a) () * * l ()* * ( ) ) l * ( ) ) * **( y bad *)
Explanation:
\(+\*+ # begin with a (* sequence (or some variation like ((* or ((**, etc.)
(?: # begin comment content
[^*(] # allow any non-* non-( characters (which begin open/close brackets)
| # also
(?:\*+[^)*]) # allow * 1+ times in a row ONLY if it's not immediately followed by ) or *
| # also
(?:\(+[^*(]) # allow ( 1+ times in a row ONLY if it's not immediately followed by * or (
)* # allow any number of these characters / character sequences
\*+\)+ # then close the comment with a *) (or some variation like **) or *))), etc.)
To capture un-nested and nested comments, simply allow comments inside of comments. ie:
p{2} = \(+\*+(?:(?:p{1})|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
in other words
p{2} = \(+\*+(?:(?:\(+\*+(?:[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+)|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
You'll see that this works on the following examples:
(* test (* one *) *)
(* a bit * ( ) * harder (* ) * () (( *) *)
(* r *( (( e **( a ) ((* l *() l *) y * bad * ( *)
To capture up to triply-nested comments, follow the pattern set by p{2}:
p{3} = \(+\*+(?:(?:p{2})|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
p{3} = \(+\*+(?:(?:\(+\*+(?:(?:\(+\*+(?:[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+)|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+)|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
Examples:
(* an (* easy (* one *) *) *)
(* only (* some (* levels (* captured *) because *) 4x *) nested *)
The pattern can be followed to allow any depth of nested comments to be captured, by defining
p{N} = \(+\*+(?:(?:p{N-1})|[^*(]|(?:\*+[^)*])|(?:\(+[^*(]))*\*+\)+
for N > 1
"""##
let stringRange = NSRange(location: 0, length: testString.utf16.count)
let matches = regex.matches(in: testString, range: stringRange)
var result: [[String]] = []
for match in matches {
var groups: [String] = []
for rangeIndex in 1 ..< match.numberOfRanges {
let nsRange = match.range(at: rangeIndex)
guard !NSEqualRanges(nsRange, NSMakeRange(NSNotFound, 0)) else { continue }
let string = (testString as NSString).substring(with: nsRange)
groups.append(string)
}
if !groups.isEmpty {
result.append(groups)
}
}
print(result)
Please keep in mind that these code samples are automatically generated and are not guaranteed to work. If you find any syntax errors, feel free to submit a bug report. For a full regex reference for Swift 5.2, please visit: https://developer.apple.com/documentation/foundation/nsregularexpression