Reputation: 3092
I have a project with a main textView and two textFields. In the main textView field there is the text to process, in the first textField you enter a regular expression and in the second textField you enter the substitution template string.
If in the second textField I enter text, all work fine, but if I enter some regex it seems that this is handled like plain text. For example entering \n\n instead of adding two newlines characters in the final text, it just enter nn.
Here is my code, it's partially based on
What am I doing wrong?
if let regex = NSRegularExpression.expresssionWith(theSearchOptions){ // theSearchOptions uses the struct below
// replace matches
let regStr = regex.stringByReplacingMatchesInString(str, options: .WithTransparentBounds, range: NSMakeRange(0, str.characters.count), withTemplate: substitution) // EDIT: substitution is the var that contains the template string
newStr = regStr
}
struct SearchOptions {
let searchString: String
var replacementString: String
let matchCase: Bool
let wholeWords: Bool
let escapeMetacharacters: Bool
}
extension NSRegularExpression {
static func expresssionWith(options: SearchOptions) -> NSRegularExpression? {
let searchString = options.searchString
let isCaseSensitive = options.matchCase // true
let isWholeWords = options.wholeWords // false
let escapeMetacharacters = options.escapeMetacharacters // false
// handle case sensitive option
var regexOption: NSRegularExpressionOptions = .CaseInsensitive
if isCaseSensitive { // if it is match case remove case sensitive option
regexOption = []
}
// put the search string in the pattern
var pattern = searchString
if escapeMetacharacters {
pattern = NSRegularExpression.escapedPatternForString(searchString)
// adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters
} else {
// no changes in the pattern
}
if isWholeWords {
pattern = "(?<!\\w)" + NSRegularExpression.escapedPatternForString(searchString) + "(?!\\w)"
}
do {
return try NSRegularExpression(pattern: pattern, options: regexOption)
} catch {
print("Error: \(error)")
return nil
}
}
}
Upvotes: 0
Views: 4418
Reputation: 47876
As you know textField does not convert user inputs, so entering \n\n
will make 4 character String \
n
\
n
.
And regex templates do not recognize much escaping sequence as compared to regex patterns.
Regular Expression Metacharacters
As you see only two metacharacters are defined: $
and \
.
And \
is defined as:
Treat the following character as a literal, suppressing any special meaning. Backslash escaping in substitution text is only required for '$' and '\', but may be used on any other character without bad effects.
This description means that any character following \
is treated as the character itself. Supplying \n\n
as a template is exactly the same as nn
.
As Wiktor Stribiżew already commented, if you want to give special meaning to some character sequences, you need to do it yourself.
if let regex = NSRegularExpression.expresssionWith(theSearchOptions){ // theSearchOptions uses the struct below
//Replace metacharacters in `substitution` (Assuming `substitution` is a var.)
substitution = substitution.stringByReplacingOccurrencesOfString("\\n", withString: "\n")
substitution = substitution.stringByReplacingOccurrencesOfString("\\r", withString: "\r")
substitution = substitution.stringByReplacingOccurrencesOfString("\\t", withString: "\t")
//You may need more...
// replace matches
let regStr = regex.stringByReplacingMatchesInString(str, options: .WithTransparentBounds, range: NSMakeRange(0, str.characters.count), withTemplate: substitution)
newStr = regStr
}
Upvotes: 1