| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See http://swift.org/LICENSE.txt for license information |
| // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| |
| |
| |
| #if DEPLOYMENT_RUNTIME_OBJC || os(Linux) |
| import Foundation |
| import XCTest |
| #else |
| import SwiftFoundation |
| import SwiftXCTest |
| #endif |
| |
| |
| |
| class TestNSRegularExpression : XCTestCase { |
| |
| static var allTests : [(String, (TestNSRegularExpression) -> () throws -> Void)] { |
| return [ |
| ("test_simpleRegularExpressions", test_simpleRegularExpressions), |
| ("test_regularExpressionReplacement", test_regularExpressionReplacement), |
| ("test_complexRegularExpressions", test_complexRegularExpressions), |
| ("test_Equal", test_Equal), |
| ("test_NSCoding", test_NSCoding), |
| ("test_defaultOptions", test_defaultOptions), |
| ("test_badPattern", test_badPattern), |
| ] |
| } |
| |
| func simpleRegularExpressionTestWithPattern(_ patternString: String, target searchString: String, looking: Bool, match: Bool, file: StaticString = #file, line: UInt = #line) { |
| do { |
| let str = NSString(string: searchString) |
| var range = NSMakeRange(0, str.length) |
| let regex = try NSRegularExpression(pattern: patternString) |
| do { |
| let lookingRange = regex.rangeOfFirstMatch(in: searchString, options: .anchored, range: range) |
| let matchRange = regex.rangeOfFirstMatch(in: searchString, options: [], range: range) |
| let lookingResult = lookingRange.location == range.location |
| let matchResult = NSEqualRanges(matchRange, range) |
| XCTAssertTrue((lookingResult && looking) || (!lookingResult && !looking), "Case 0 simple regex \(patternString) in \(searchString) looking \(lookingResult) should be \(looking)", file: file, line: line) |
| XCTAssertTrue((matchResult && match) || (!matchResult && !match), "Case 0 simple regex \(patternString) in \(searchString) match \(matchResult) should be \(match)", file: file, line: line) |
| } |
| do { |
| let lookingRange = str.range(of: patternString, options: [.regularExpression, .anchored], range: range, locale: nil) |
| let matchRange = str.range(of: patternString, options: .regularExpression, range: range, locale: nil) |
| let lookingResult = lookingRange.location == range.location |
| let matchResult = NSEqualRanges(matchRange, range) |
| |
| XCTAssertTrue((lookingResult && looking) || (!lookingResult && !looking), "Case 1 simple regex \(patternString) in \(searchString) looking \(lookingResult) should be \(looking)", file: file, line: line) |
| XCTAssertTrue((matchResult && match) || (!matchResult && !match), "Case 1 simple regex \(patternString) in \(searchString) match \(matchResult) should be \(match)", file: file, line: line) |
| } |
| do { |
| let prefixString = "when in the course of human events " |
| let suffixString = " becomes necessary" |
| let searchString2 = NSString(string: "\(prefixString)\(searchString)\(suffixString)") |
| range.location = prefixString.utf16.count |
| let lookingRange = searchString2.range(of: patternString, options: [.regularExpression, .anchored], range: range, locale: nil) |
| let matchRange = searchString2.range(of: patternString, options: [.regularExpression], range: range, locale: nil) |
| |
| let lookingResult = lookingRange.location == range.location |
| let matchResult = NSEqualRanges(matchRange, range) |
| |
| XCTAssertTrue((lookingResult && looking) || (!lookingResult && !looking), "Case 2 simple regex \(patternString) in \(searchString) looking \(lookingResult) should be \(looking)", file: file, line: line) |
| XCTAssertTrue((matchResult && match) || (!matchResult && !match), "Case 2 simple regex \(patternString) in \(searchString) match \(matchResult) should be \(match)", file: file, line: line) |
| } |
| if !patternString.hasPrefix(".") { |
| let prefixString = "when in the course of human events " |
| let suffixString = " becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary becomes necessary" |
| let searchString2 = NSString(string: "\(prefixString)\(searchString)\(suffixString)") |
| range.location = prefixString.utf16.count |
| let lookingRange = searchString2.range(of: patternString, options: [.regularExpression, .anchored], range: NSMakeRange(range.location, range.length + suffixString.utf16.count), locale: nil) |
| let matchRange = searchString2.range(of: patternString, options: .regularExpression, range: NSMakeRange(range.location, range.length + suffixString.utf16.count), locale: nil) |
| let lookingResult = lookingRange.location == range.location |
| let matchResult = lookingResult && (matchRange.length >= range.length) |
| |
| XCTAssertTrue((lookingResult && looking) || (!lookingResult && !looking), "Case 3 simple regex \(patternString) in \(searchString) looking \(lookingResult) should be \(looking)", file: file, line: line) |
| XCTAssertTrue((matchResult && match) || (!matchResult && !match), "Case 3 simple regex \(patternString) in \(searchString) match \(matchResult) should be \(match)", file: file, line: line) |
| } |
| |
| do { |
| let prefixString = "when in the course of human events " |
| let suffixString = " becomes necessary’" |
| let searchString2 = NSString(string: "\(prefixString)\(searchString)\(suffixString)") |
| range.location = prefixString.utf16.count |
| let lookingRange = searchString2.range(of: patternString, options: [.regularExpression, .anchored], range: range, locale: nil) |
| let matchRange = searchString2.range(of: patternString, options: [.regularExpression], range: range, locale: nil) |
| |
| let lookingResult = lookingRange.location == range.location |
| let matchResult = NSEqualRanges(matchRange, range) |
| |
| XCTAssertTrue((lookingResult && looking) || (!lookingResult && !looking), "Case 4 simple regex \(patternString) in \(searchString) looking \(lookingResult) should be \(looking)", file: file, line: line) |
| XCTAssertTrue((matchResult && match) || (!matchResult && !match), "Case 4 simple regex \(patternString) in \(searchString) match \(matchResult) should be \(match)", file: file, line: line) |
| } |
| } catch { |
| XCTFail("Unable to build regular expression for pattern \(patternString)", file: file, line: line) |
| } |
| } |
| |
| func test_simpleRegularExpressions() { |
| simpleRegularExpressionTestWithPattern("st(abc)ring", target:"stabcring thing", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("st(abc)ring", target:"stabcring", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("st(abc)ring", target:"stabcrung", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("st(abc)*ring", target:"string", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("st(abc)*ring", target:"stabcring", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("st(abc)*ring", target:"stabcabcring", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("st(abc)*ring", target:"stabcabcdring", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("st(abc)*ring", target:"stabcabcabcring etc.", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("a*", target:"", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a*", target:"b", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern(".", target:"abc", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("...", target:"abc", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("....", target:"abc", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern(".*", target:"abcxyz123", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab.*xyz", target:"abcdefghij", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("ab.*xyz", target:"abcdefg...wxyz", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab.*xyz", target:"abcde...wxyz...abc..xyz", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab.*xyz", target:"abcde...wxyz...abc..xyz...", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("abc*", target:"ab", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("abc*", target:"abccccc", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("[1-6]", target:"1", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("[1-6]", target:"3", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("[1-6]", target:"7", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("a[1-6]", target:"a3", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a[1-6]", target:"a3", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a[1-6]b", target:"a3b", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a[0-9]*b", target:"a123b", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a[0-9]*b", target:"abc", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("[\\p{Nd}]*", target:"123456", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("[\\p{Nd}]*", target:"a123456", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("[a][b][[:Zs:]]*", target:"ab ", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|b)", target:"a", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|b)", target:"b", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|b)", target:"c", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("a|b", target:"b", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|b|c)*", target:"aabcaaccbcabc", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|b|c)*", target:"aabcaaccbcabdc", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("(a(b|c|d)(x|y|z)*|123)", target:"ac", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a(b|c|d)(x|y|z)*|123)", target:"123", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|(1|2)*)(b|c|d)(x|y|z)*|123", target:"123", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("(a|(1|2)*)(b|c|d)(x|y|z)*|123", target:"222211111czzzzw", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("ab+", target:"abbc", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("ab+c", target:"ac", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("b+", target:"", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("(abc|def)+", target:"defabc", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern(".+y", target:"zippity dooy dah ", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern(".+y", target:"zippity dooy", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab?", target:"ab", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab?", target:"a", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("ab?", target:"ac", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("ab?", target:"abb", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern("a(b|c)?d", target:"abd", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a(b|c)?d", target:"acd", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a(b|c)?d", target:"ad", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern("a(b|c)?d", target:"abcd", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("a(b|c)?d", target:"ab", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern(".*\\Ax", target:"xyz", looking:true, match:false) |
| simpleRegularExpressionTestWithPattern(".*\\Ax", target:" xyz", looking:false, match:false) |
| simpleRegularExpressionTestWithPattern("\\\\\\|\\(\\)\\[\\{\\~\\$\\*\\+\\?\\.", target:"\\|()[{~$*+?.", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern(NSRegularExpression.escapedPattern(for: "+\\{}[].^$?#<=!&*()"), target:"+\\{}[].^$?#<=!&*()", looking:true, match:true) |
| simpleRegularExpressionTestWithPattern(NSRegularExpression.escapedPattern(for: "+\\{}[].^$?#<=!&*()"), target:"+\\{}[].^$?#<=!&*() abc", looking:true, match:false) |
| } |
| |
| func replaceRegularExpressionTest(_ patternString: String, _ patternOptions: NSRegularExpression.Options, _ searchString: String, _ searchOptions: NSRegularExpression.MatchingOptions, _ searchRange: NSRange, _ templ: String, _ numberOfMatches: Int, _ result: String, file: StaticString = #file, line: UInt = #line) { |
| do { |
| let regex = try NSRegularExpression(pattern: patternString, options: patternOptions) |
| let mutableString = NSMutableString(string: searchString) |
| let matchCount = regex.replaceMatches(in: mutableString, options: searchOptions, range: searchRange, withTemplate: templ) |
| let replacedString = regex.stringByReplacingMatches(in: searchString, options: searchOptions, range: searchRange, withTemplate: templ) |
| XCTAssertEqual(numberOfMatches, matchCount, "Regex replace \(patternString) in \(searchString) with \(templ) number \(matchCount) should be \(numberOfMatches)", file: file, line: line) |
| XCTAssertEqual(result, replacedString, "Regex replace \(patternString) in \(searchString) with \(templ) replaced \(replacedString) should be \(result)", file: file, line: line) |
| XCTAssertEqual(NSString(string: result), mutableString, "Regex replace \(patternString) in \(searchString) with \(templ) mutated \(mutableString) should be \(result)", file: file, line: line) |
| } catch { |
| XCTFail("Unable to construct regular expression from \(patternString) options \(patternOptions)", file: file, line: line) |
| } |
| } |
| |
| func test_regularExpressionReplacement() { |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This is the way.", [], NSMakeRange(0, 16), "foo", 0, "This is the way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "foo", 1, "This this is foo way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "$0", 1, "This this is the the way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*$0*", 1, "This this is *the the* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*$1*", 1, "This this is *the* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*$2*", 1, "This this is ** way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*$10*", 1, "This this is *the0* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*$*", 1, "This this is *$* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), NSRegularExpression.escapedTemplate(for: "*$1*"), 1, "This this is *$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), NSRegularExpression.escapedTemplate(for: "*\\$1*"), 1, "This this is *\\$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*\\$1*", 1, "This this is *$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), "*\\\\\\$1*", 1, "This this is *\\$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "$0", 2, "This this is the the way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*$0*", 2, "*This this* is *the the* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*$1*", 2, "*This* is *the* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*$2*", 2, "** is ** way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*$10*", 2, "*This0* is *the0* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*$*", 2, "*$* is *$* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), NSRegularExpression.escapedTemplate(for: "*$1*"), 2, "*$1* is *$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), NSRegularExpression.escapedTemplate(for: "*\\$1*"), 2, "*\\$1* is *\\$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*\\$1*", 2, "*$1* is *$1* way.") |
| replaceRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), "*\\\\\\$1*", 2, "*\\$1* is *\\$1* way.") |
| replaceRegularExpressionTest("([1-9]a)([1-9]b)([1-9]c)([1-9]d)([1-9]e)([1-9]f)", [], "9a3b4c8d3e1f,9a3b4c8d3e1f", [], NSMakeRange(0,25), "$2$4 is your key", 2, "3b8d is your key,3b8d is your key") |
| replaceRegularExpressionTest("([1-9]a)([1-9]b)([1-9]c)([1-9]d)([1-9]e)([1-9]f)([1-9]z)", [], "9a3b4c8d3e1f2z,9a3b4c8d3e1f2z", [], NSMakeRange(0,29), "$2$4$1 is your key", 2, "3b8d9a is your key,3b8d9a is your key") |
| } |
| |
| func complexRegularExpressionTest(_ patternString: String, _ patternOptions: NSRegularExpression.Options, _ searchString: String, _ searchOptions: NSRegularExpression.MatchingOptions, _ searchRange: NSRange, _ numberOfMatches: Int, _ firstMatchOverallRange: NSRange, _ firstMatchFirstCaptureRange: NSRange, _ firstMatchLastCaptureRange: NSRange, file: StaticString = #file, line: UInt = #line) { |
| do { |
| let regex = try NSRegularExpression(pattern: patternString, options: patternOptions) |
| let matches = regex.matches(in: searchString, options: searchOptions, range: searchRange) |
| let matchCount = regex.numberOfMatches(in: searchString, options: searchOptions, range: searchRange) |
| let firstResult = regex.firstMatch(in: searchString, options: searchOptions, range: searchRange) |
| let firstRange = regex.rangeOfFirstMatch(in: searchString, options: searchOptions, range: searchRange) |
| let captureCount = regex.numberOfCaptureGroups |
| |
| XCTAssertEqual(numberOfMatches, matches.count, "Complex regex \(patternString) in \(searchString) number \(matches.count)/\(matchCount) should be \(numberOfMatches)", file: file, line: line) |
| XCTAssertTrue(NSEqualRanges(firstRange, firstMatchOverallRange), "Complex regex \(patternString) in \(searchString) match range \(NSStringFromRange(firstRange)) should be \(NSStringFromRange(firstMatchOverallRange))", file: file, line: line) |
| for result in matches { |
| let rangeCount = result.numberOfRanges |
| XCTAssertEqual(captureCount + 1, rangeCount, "Complex regex \(patternString) in \(searchString) mismatch \(captureCount) groups but \(result) has \(rangeCount) ranges", file: file, line: line) |
| } |
| if let first = firstResult, matches.count > 0 { |
| XCTAssertTrue(NSEqualRanges(first.range, firstMatchOverallRange), "Complex regex \(patternString) in \(searchString) match range \(NSStringFromRange(first.range)) should be \(NSStringFromRange(firstMatchOverallRange))", file: file, line: line) |
| if captureCount > 0 { |
| XCTAssertTrue(NSEqualRanges(first.range(at: 1), firstMatchFirstCaptureRange), "Complex regex \(patternString) in \(searchString) match range \(first.range(at: 1)) should be \(NSStringFromRange(firstMatchFirstCaptureRange))", file: file, line: line) |
| } else { |
| XCTAssertTrue(NSEqualRanges(firstMatchFirstCaptureRange, NSMakeRange(NSNotFound, 0)), "Complex regex \(patternString) in \(searchString) no captures should be \(NSStringFromRange(firstMatchFirstCaptureRange))", file: file, line: line) |
| } |
| if captureCount > 1 { |
| XCTAssertTrue(NSEqualRanges(first.range(at: captureCount), firstMatchLastCaptureRange), "Complex regex \(patternString) in \(searchString) last capture range \(NSStringFromRange(first.range(at: captureCount))) should be \(NSStringFromRange(firstMatchLastCaptureRange))", file: file, line: line) |
| } |
| } |
| } catch { |
| XCTFail("Unable to construct regular expression from \(patternString) options \(patternOptions)", file: file, line: line) |
| } |
| } |
| |
| func test_complexRegularExpressions() { |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This is the way.", [], NSMakeRange(0, 16), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", [], NSMakeRange(0, 24), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", [], NSMakeRange(0, 20), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", .withTransparentBounds, NSMakeRange(0, 20), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "xThis this is the theway.", [], NSMakeRange(1, 20), 1, NSMakeRange(14, 7), NSMakeRange(14, 3), NSMakeRange(14, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", [], NSMakeRange(1, 20), 2, NSMakeRange(1, 9), NSMakeRange(1, 4), NSMakeRange(1, 4)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", .withTransparentBounds, NSMakeRange(1, 20), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest(NSRegularExpression.escapedPattern(for: "\\b(th[a-z]+) \\1\\b"), [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest(NSRegularExpression.escapedPattern(for: "\\b(th[a-z]+) \\1\\b"), [], "x\\b(th[a-z]+) \\1\\by", [], NSMakeRange(0, 19), 1, NSMakeRange(1, 17), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .ignoreMetacharacters, "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .ignoreMetacharacters, "x\\b(th[a-z]+) \\1\\by", [], NSMakeRange(0, 19), 1, NSMakeRange(1, 17), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", [], NSMakeRange(13, 7), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", .withoutAnchoringBounds, NSMakeRange(13, 7), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "this this\nthe the", [], NSMakeRange(0, 17), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", .anchorsMatchLines, "this this\nthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", .anchorsMatchLines, "this this\rthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [.useUnixLineSeparators, .anchorsMatchLines], "this this\nthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [.useUnixLineSeparators, .anchorsMatchLines], "this this\rthe the", [], NSMakeRange(0, 17), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This is the way.", [], NSMakeRange(0, 16), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", .caseInsensitive, "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This\nthis is the\nthe way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", .dotMatchesLineSeparators, "This\nthis is the\nthe way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [.dotMatchesLineSeparators, .caseInsensitive], "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+).\n#the first expression repeats\n\\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\n#the first expression repeats\n\\1\\b", .allowCommentsAndWhitespace, "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "This this is the the way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", [], NSMakeRange(0, 24), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", [], NSMakeRange(0, 20), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "This this is the theway.", .withTransparentBounds, NSMakeRange(0, 20), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", [], "xThis this is the theway.", [], NSMakeRange(1, 20), 1, NSMakeRange(14, 7), NSMakeRange(14, 3), NSMakeRange(14, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", [], NSMakeRange(1, 20), 2, NSMakeRange(1, 9), NSMakeRange(1, 4), NSMakeRange(1, 4)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .caseInsensitive, "xThis this is the theway.", .withTransparentBounds, NSMakeRange(1, 20), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest(NSRegularExpression.escapedPattern(for: "\\b(th[a-z]+) \\1\\b"), [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest(NSRegularExpression.escapedPattern(for: "\\b(th[a-z]+) \\1\\b"), [], "x\\b(th[a-z]+) \\1\\by", [], NSMakeRange(0, 19), 1, NSMakeRange(1, 17), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .ignoreMetacharacters, "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+) \\1\\b", .ignoreMetacharacters, "x\\b(th[a-z]+) \\1\\by", [], NSMakeRange(0, 19), 1, NSMakeRange(1, 17), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", [], NSMakeRange(13, 7), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "This this is the the way.", .withoutAnchoringBounds, NSMakeRange(13, 7), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [], "this this\nthe the", [], NSMakeRange(0, 17), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", .anchorsMatchLines, "this this\nthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", .anchorsMatchLines, "this this\rthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [.useUnixLineSeparators, .anchorsMatchLines], "this this\nthe the", [], NSMakeRange(0, 17), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("^(th[a-z]+) \\1$", [.useUnixLineSeparators, .anchorsMatchLines], "this this\rthe the", [], NSMakeRange(0, 17), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This is the way.", [], NSMakeRange(0, 16), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", .caseInsensitive, "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [], "This\nthis is the\nthe way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", .dotMatchesLineSeparators, "This\nthis is the\nthe way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\\1\\b", [.dotMatchesLineSeparators, .caseInsensitive], "Thisxthis is thexthe way.", [], NSMakeRange(0, 25), 2, NSMakeRange(0, 9), NSMakeRange(0, 4), NSMakeRange(0, 4)) |
| |
| complexRegularExpressionTest("\\b(th[a-z]+).\n#the first expression repeats\n\\1\\b", [], "This this is the the way.", [], NSMakeRange(0, 25), 0, NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("\\b(th[a-z]+).\n#the first expression repeats\n\\1\\b", .allowCommentsAndWhitespace, "This this is the the way.", [], NSMakeRange(0, 25), 1, NSMakeRange(13, 7), NSMakeRange(13, 3), NSMakeRange(13, 3)) |
| complexRegularExpressionTest("(a(b|c|d)(x|y|z)*|123)", [], "abx", [], NSMakeRange(0, 3), 1, NSMakeRange(0, 3), NSMakeRange(0, 3), NSMakeRange(2, 1)) |
| complexRegularExpressionTest("(a(b|c|d)(x|y|z)*|123)", [], "123", [], NSMakeRange(0, 3), 1, NSMakeRange(0, 3), NSMakeRange(0, 3), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("a(b|c|d)(x|y|z)*|123", [], "123", [], NSMakeRange(0, 3), 1, NSMakeRange(0, 3), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("a(b|c|d)(x|y|z)*", [], "abx", [], NSMakeRange(0, 3), 1, NSMakeRange(0, 3), NSMakeRange(1, 1), NSMakeRange(2, 1)) |
| complexRegularExpressionTest("(a(b|c|d)(x|y|z)*|123)", [], "abxy", [], NSMakeRange(0, 4), 1, NSMakeRange(0, 4), NSMakeRange(0, 4), NSMakeRange(3, 1)) |
| complexRegularExpressionTest("a(b|c|d)(x|y|z)*", [], "abxy", [], NSMakeRange(0, 4), 1, NSMakeRange(0, 4), NSMakeRange(1, 1), NSMakeRange(3, 1)) |
| complexRegularExpressionTest("(a|b)x|123|(c|d)y", [], "123dy", [], NSMakeRange(0, 5), 2, NSMakeRange(0, 3), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("(a|b)x|123|(c|d)y", [], "903847123", [], NSMakeRange(0, 9), 1, NSMakeRange(6, 3), NSMakeRange(NSNotFound, 0), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("(a|b)x|123|(c|d)y", [], "axcy", [], NSMakeRange(0, 4), 2, NSMakeRange(0, 2), NSMakeRange(0, 1), NSMakeRange(NSNotFound, 0)) |
| complexRegularExpressionTest("(a|b)x|123|(c|d)y", [], "cya", [], NSMakeRange(0, 3), 1, NSMakeRange(0, 2), NSMakeRange(NSNotFound, 0), NSMakeRange(0, 1)) |
| } |
| |
| func test_Equal() { |
| var regularExpressionA = try! NSRegularExpression(pattern: "[a-z]+", options: []) |
| var regularExpressionB = try! NSRegularExpression(pattern: "[a-z]+", options: []) |
| XCTAssertTrue(regularExpressionA == regularExpressionB) |
| XCTAssertFalse(regularExpressionA === regularExpressionB) |
| |
| regularExpressionA = try! NSRegularExpression(pattern: "[a-z]+", options: .caseInsensitive) |
| regularExpressionB = try! NSRegularExpression(pattern: "[a-z]+", options: .caseInsensitive) |
| XCTAssertTrue(regularExpressionA == regularExpressionB) |
| XCTAssertFalse(regularExpressionA === regularExpressionB) |
| |
| regularExpressionA = try! NSRegularExpression(pattern: "[a-z]+", options: [.caseInsensitive, .allowCommentsAndWhitespace]) |
| regularExpressionB = try! NSRegularExpression(pattern: "[a-z]+", options: [.caseInsensitive, .allowCommentsAndWhitespace]) |
| XCTAssertTrue(regularExpressionA == regularExpressionB) |
| XCTAssertFalse(regularExpressionA === regularExpressionB) |
| |
| regularExpressionA = try! NSRegularExpression(pattern: "[a-z]+", options: .caseInsensitive) |
| regularExpressionB = try! NSRegularExpression(pattern: "[a-z]+", options: [.caseInsensitive, .allowCommentsAndWhitespace]) |
| XCTAssertFalse(regularExpressionA == regularExpressionB) |
| XCTAssertFalse(regularExpressionA === regularExpressionB) |
| |
| regularExpressionA = try! NSRegularExpression(pattern: "[a-y]+", options: .caseInsensitive) |
| regularExpressionB = try! NSRegularExpression(pattern: "[a-z]+", options: .caseInsensitive) |
| XCTAssertFalse(regularExpressionA == regularExpressionB) |
| XCTAssertFalse(regularExpressionA === regularExpressionB) |
| } |
| |
| func test_NSCoding() { |
| let regularExpressionA = try! NSRegularExpression(pattern: "[a-z]+", options: [.caseInsensitive, .allowCommentsAndWhitespace]) |
| let regularExpressionB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: regularExpressionA)) as! NSRegularExpression |
| XCTAssertEqual(regularExpressionA, regularExpressionB, "Archived then unarchived `NSRegularExpression` must be equal.") |
| } |
| |
| // Check all of the following functions do not need to be passed options: |
| func test_defaultOptions() { |
| let pattern = ".*fatal error: (.*): file (.*), line ([0-9]+)$" |
| let text = "fatal error: Some message: file /tmp/foo.swift, line 123" |
| let regex = try? NSRegularExpression(pattern: pattern) |
| XCTAssertNotNil(regex) |
| let range = NSRange(text.startIndex..., in: text) |
| regex!.enumerateMatches(in: text, range: range, using: {_,_,_ in }) |
| XCTAssertEqual(regex!.matches(in: text, range: range).first?.numberOfRanges, 4) |
| XCTAssertEqual(regex!.numberOfMatches(in: text, range: range), 1) |
| XCTAssertEqual(regex!.firstMatch(in: text, range: range)?.numberOfRanges, 4) |
| XCTAssertEqual(regex!.rangeOfFirstMatch(in: text, range: range), |
| NSMakeRange(0, 56)) |
| XCTAssertEqual(regex!.stringByReplacingMatches(in: text, range: range, withTemplate: "$1-$2-$3"), |
| "Some message-/tmp/foo.swift-123") |
| let str = NSMutableString(string: text) |
| XCTAssertEqual(regex!.replaceMatches(in: str, range: range, withTemplate: "$1-$2-$3"), 1) |
| } |
| |
| func test_badPattern() { |
| do { |
| _ = try NSRegularExpression(pattern: "(", options: []) |
| XCTFail() |
| } catch { |
| let err = String(describing: error) |
| XCTAssertEqual(err, "Error Domain=NSCocoaErrorDomain Code=2048 \"(null)\" UserInfo={NSInvalidValue=(}") |
| } |
| } |
| } |