问题
I'm currently implementing NSRegularExpressions
to check for patterns inside a UITextView
string in my project.
The patterns check and operations are working as expected; for example: I'm trying to find the regular **bold**
markdown pattern and if I find it I apply some text attributed to the range, and it works as expected.
I have though came across a problem. I don't know how to run multiple patterns at once and apply different operations for each pattern found.
In my UITextView
delegate textViewDidChange
or shouldChangeTextIn range: NSRange
I am running the bold pattern check \\*{2}([\\w ]+)\\*{2}
but then I am as well running the italic pattern check \\_{1}([\\w ]+)\\_{1}
, looping again through the UITextView text
.
I have implemented the following custom function, that applies the passed in regex
to the string, but I have to call this function multiple times to check for each pattern, that's why I'd love to put the pattern check into one single, then "parse" each match
.
fileprivate func regularExpression(regex: NSRegularExpression, type: TypeAttributes) {
let str = inputTextView.attributedText.string
let results = regex.matches(in: str, range: NSRange(str.startIndex..., in: str))
_ = results.map { self.applyAttributes(range: $0.range, type: type) }
}
Thanks.
EDIT
I can "merge" both patterns with the |
operand like the following:
private let combinedPattern = "\\*{2}([\\w ]+)\\*{2}|\\_{1}([\\w ]+)\\_{1}"
but my problem is to know which pattern was found the \\*{2}([\\w ]+)\\*{2}
one or the \\_{1}([\\w ]+)\\_{1}
回答1:
If you use the combined pattern you have the results in different range of the match result.
If you want to access the first capture group (the bold pattern) you need to access the range at 1. When the match matches the second group you will have the first with an invalid range, so you need to check if it's valid of not this way:
results.forEach {
var range = $0.range(at: 1)
if range.location + range.length < str.count {
self.applyAttributes(range: range, type: .bold)
}
range = $0.range(at: 2)
if range.location + range.length < str.count {
self.applyAttributes(range: range, type: .italic)
}
}
After that you can extend your TypeAttributes
enum to return the index range that is linked to your regular expression:
extension NSRange {
func isValid(for string:String) -> Bool {
return location + length < string.count
}
}
let attributes: [TypeAttributes] = [.bold, .italic]
results.forEach { match in
attributes.enumerated().forEach { index, attribute in
let range = match.range(at: index+1)
if range.isValid(for: str) {
self.applyAttributes(range: range, type: attribute[index])
}
}
}
来源:https://stackoverflow.com/questions/50326149/which-nsregularexpression-was-found-using-the-operator