TRAVIS_OS_NAME=osx <<<<<< ENV LICENSE Package.swift Sources/RegEx/RegEx.swift Tests/LinuxMain.swift Tests/RegExTests/CaptureGroupTests.swift Tests/RegExTests/ExponentTests.swift Tests/RegExTests/IteratorTests.swift Tests/RegExTests/NoOverlapTests.swift Tests/RegExTests/ReplacementTests.swift Tests/RegExTests/XCTestManifests.swift <<<<<< network # path=RegExTests.xctest.coverage.txt /Users/travis/build/eneko/RegEx/Tests/RegExTests/CaptureGroupTests.swift: 1| |// 2| |// CaptureGroupTests.swift 3| |// RegExTests 4| |// 5| |// Created by Eneko Alonso on 5/18/19. 6| |// 7| | 8| |import XCTest 9| |import RegEx 10| | 11| |class CaptureGroupTests: XCTestCase { 12| | 13| | /// Capturing group test 14| | /// https://www.regular-expressions.info/refcapture.html 15| 1| func testCapturingGroup() throws { 16| 1| let str = "abcabcabc" 17| 1| let regex = try RegEx(pattern: "(abc){3}") 18| 1| let matches = regex.matches(in: str) 19| 1| 20| 1| XCTAssertEqual(matches.count, 1) 21| 1| XCTAssertEqual(matches[0].values.first, "abcabcabc") 22| 1| XCTAssertEqual(matches[0].ranges.count, 2) 23| 1| XCTAssertEqual(matches[0].values[1], "abc") 24| 1| } 25| | 26| | /// Non-Capturing group test 27| | /// https://www.regular-expressions.info/refcapture.html 28| 1| func testNonCapturingGroup() throws { 29| 1| let str = "abcabcabc" 30| 1| let regex = try RegEx(pattern: "(?:abc){3}") 31| 1| let matches = regex.matches(in: str) 32| 1| 33| 1| XCTAssertEqual(matches.count, 1) 34| 1| XCTAssertEqual(matches[0].values.first, "abcabcabc") 35| 1| XCTAssertEqual(matches[0].ranges.count, 1) 36| 1| } 37| | 38| | /// Backreference group test 39| | /// https://www.regular-expressions.info/refcapture.html 40| 1| func testBackreferenceFirstGroup() throws { 41| 1| let regex = try RegEx(pattern: #"(abc|def)=\1"#) 42| 1| XCTAssertTrue(regex.test("abc=abc")) 43| 1| XCTAssertTrue(regex.test("def=def")) 44| 1| XCTAssertFalse(regex.test("abc=def")) 45| 1| XCTAssertFalse(regex.test("def=abc")) 46| 1| } 47| | 48| | /// Backreference group test 49| | /// https://www.regular-expressions.info/refcapture.html 50| 1| func testBackreferenceSecondGroup() throws { 51| 1| let regex = try RegEx(pattern: #"(a)(b)(c)(d)\2"#) 52| 1| XCTAssertTrue(regex.test("abcdb")) 53| 1| XCTAssertFalse(regex.test("abcde")) 54| 1| } 55| | 56| | /// Failed backreference 57| | /// https://www.regular-expressions.info/refcapture.html 58| 1| func testFailedBackreference() throws { 59| 1| let regex = try RegEx(pattern: #"(a)?\1"#) 60| 1| XCTAssertEqual(regex.matches(in: "aa")[0].values[0], "aa") 61| 1| XCTAssertTrue(regex.matches(in: "b").isEmpty) 62| 1| } 63| | 64| | /// Case insensitive group 65| | /// https://javascript.info/regexp-groups 66| 1| func testCaseInsensitiveGroup() throws { 67| 1| let regex = try RegEx(pattern: "(go)+", options: .caseInsensitive) 68| 1| XCTAssertEqual(regex.matches(in: "Gogogo now!")[0].values[0], "Gogogo") 69| 1| } 70| | 71| | /// Email regex 72| | /// https://javascript.info/regexp-groups 73| 1| func testEmail() throws { 74| 1| let regex = try RegEx(pattern: #"[-.\w]+@([\w-]+\.)+[\w-]{2,20}"#) 75| 1| let matches = regex.matches(in: "my@mail.com @ his@site.com.uk") 76| 1| XCTAssertEqual(matches[0].values[0], "my@mail.com") 77| 1| XCTAssertEqual(matches[1].values[0], "his@site.com.uk") 78| 1| } 79| | 80| | /// Nested groups 81| | /// https://javascript.info/regexp-groups 82| 1| func testNestedGroups() throws { 83| 1| let regex = try RegEx(pattern: #"<(([a-z]+)\s*([^>]*))>"#) 84| 1| let matches = regex.matches(in: #""#) 85| 1| XCTAssertEqual(matches[0].values[0], "") 86| 1| XCTAssertEqual(matches[0].values[1], "span class=\"my\"") 87| 1| XCTAssertEqual(matches[0].values[2], "span") 88| 1| XCTAssertEqual(matches[0].values[3], "class=\"my\"") 89| 1| } 90| | 91| | /// Missing groups 92| | /// https://javascript.info/regexp-groups 93| 1| func testMissingGroups() throws { 94| 1| let regex = try RegEx(pattern: "a(z)?(c)?") 95| 1| let matches = regex.matches(in: "a") 96| 1| XCTAssertEqual(matches.count, 1) 97| 1| XCTAssertEqual(matches[0].values.count, 3) 98| 1| XCTAssertEqual(matches[0].values[0], "a") 99| 1| XCTAssertNil(matches[0].values[1]) // no value for group (z)? 100| 1| XCTAssertNil(matches[0].values[2]) // no value for group (c)? 101| 1| } 102| | 103| | /// Missing groups 104| | /// https://javascript.info/regexp-groups 105| 1| func testMissingGroupsACK() throws { 106| 1| let regex = try RegEx(pattern: "a(z)?(c)?") 107| 1| let matches = regex.matches(in: "ack") 108| 1| XCTAssertEqual(matches.count, 1) 109| 1| XCTAssertEqual(matches[0].values.count, 3) 110| 1| XCTAssertEqual(matches[0].values[0], "ac") 111| 1| XCTAssertNil(matches[0].values[1]) // no value for group (z)? 112| 1| XCTAssertEqual(matches[0].values[2], "c") 113| 1| } 114| | 115| | /// Named groups 116| | /// https://javascript.info/regexp-groups 117| 1| func testNamedGroups() throws { 118| 1| let regex = try RegEx(pattern: "(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})") 119| 1| let matches = regex.matches(in: "2019-04-30") 120| 1| XCTAssertEqual(matches[0].values[0], "2019-04-30") 121| 1| XCTAssertEqual(matches[0].values[1], "2019") 122| 1| XCTAssertEqual(matches[0].values[2], "04") 123| 1| XCTAssertEqual(matches[0].values[3], "30") 124| 1| } 125| | 126| |} /Users/travis/build/eneko/RegEx/Tests/RegExTests/ExponentTests.swift: 1| |// 2| |// ExponentTests.swift 3| |// RegExTests 4| |// 5| |// Created by Eneko Alonso on 5/13/19. 6| |// 7| | 8| |import XCTest 9| |import RegEx 10| | 11| |final class ExponentTests: XCTestCase { 12| | 13| 1| func testExponents() throws { 14| 1| let str = "16^32=2^128" 15| 1| let regex = try RegEx(pattern: #"\d+\^(\d+)"#) 16| 1| let matches = regex.matches(in: str) 17| 1| 18| 1| XCTAssertEqual(matches.count, 2) 19| 1| 20| 1| XCTAssertEqual(matches[0].values.first, "16^32") 21| 1| XCTAssertEqual(matches[0].ranges.count, 2) 22| 1| XCTAssertEqual(matches[0].values[1], "32") 23| 1| 24| 1| XCTAssertEqual(matches[1].values.first, "2^128") 25| 1| XCTAssertEqual(matches[1].ranges.count, 2) 26| 1| XCTAssertEqual(matches[1].values[1], "128") 27| 1| } 28| | 29| 1| func testExponentsStarStar() throws { 30| 1| let str = "16**32=2**128" 31| 1| let regex = try RegEx(pattern: #"\d+\*\*(\d+)"#) 32| 1| let matches = regex.matches(in: str) 33| 1| 34| 1| XCTAssertEqual(matches.count, 2) 35| 1| 36| 1| XCTAssertEqual(matches[0].values.first, "16**32") 37| 1| XCTAssertEqual(matches[0].ranges.count, 2) 38| 1| XCTAssertEqual(matches[0].values[1], "32") 39| 1| 40| 1| XCTAssertEqual(matches[1].values.first, "2**128") 41| 1| XCTAssertEqual(matches[1].ranges.count, 2) 42| 1| XCTAssertEqual(matches[1].values[1], "128") 43| 1| } 44| | 45| 1| func testExact() throws { 46| 1| let str = "16^32" 47| 1| let regex = try RegEx(pattern: #"^\d+\^(\d+)$"#) 48| 1| XCTAssertTrue(regex.test(str)) 49| 1| } 50| | 51| 1| func testExactFails() throws { 52| 1| let str = "16^32=2^128" 53| 1| let regex = try RegEx(pattern: #"^\d+\^(\d+)$"#) 54| 1| XCTAssertFalse(regex.test(str)) 55| 1| } 56| |} /Users/travis/build/eneko/RegEx/Tests/RegExTests/IteratorTests.swift: 1| |// 2| |// IteratorTests.swift 3| |// RegExTests 4| |// 5| |// Created by Eneko Alonso on 5/18/19. 6| |// 7| | 8| |import XCTest 9| |import RegEx 10| | 11| |class IteratorTests: XCTestCase { 12| | 13| | let loremIpsum = """ 14| | Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec odio. Quisque volutpat 15| | mattis eros. Nullam malesuada erat ut turpis. Suspendisse urna nibh, viverra non, 16| | semper suscipit, posuere a, pede. 17| | 18| | Donec nec justo eget felis facilisis fermentum. Aliquam porttitor mauris sit amet orci. 19| | Aenean dignissim pellentesque felis. 20| | 21| | Morbi in sem quis dui placerat ornare. Pellentesque odio nisi, euismod in, pharetra a, 22| | ultricies in, diam. Sed arcu. Cras consequat. 23| | 24| | Praesent dapibus, neque id cursus faucibus, tortor neque egestas auguae, eu vulputate 25| | magna eros eu erat. Aliquam erat volutpat. Nam dui mi, tincidunt quis, accumsan 26| | porttitor, facilisis luctus, metus. 27| | 28| | Phasellus ultrices nulla quis nibh. Quisque a lectus. Donec consectetuer ligula 29| | vulputate sem tristique cursus. Nam nulla quam, gravida non, commodo a, sodales sit 30| | amet, nisi. 31| | """ 32| | 33| | let regex = try? RegEx(pattern: #"[a-zA-Z]+m\b"#) 34| | 35| 1| func testOneByOne() { 36| 1| let first = regex?.firstMatch(in: loremIpsum) 37| 1| XCTAssertEqual(first?.values[0], "Lorem") 38| 1| let nextIndex = first?.ranges[0]?.upperBound 39| 1| XCTAssertEqual(regex?.firstMatch(in: loremIpsum, from: nextIndex)?.values[0], "ipsum") 40| 1| } 41| | 42| 1| func testIterator() throws { 43| 1| let regex = try RegEx(pattern: #"[a-zA-Z]+m\b"#) 44| 1| let iterator = regex.iterator(for: loremIpsum) 45| 1| XCTAssertEqual(iterator.next()?.values[0], "Lorem") 46| 1| XCTAssertEqual(iterator.next()?.values[0], "ipsum") 47| 1| XCTAssertEqual(iterator.next()?.values[0], "Nullam") 48| 1| } 49| |} /Users/travis/build/eneko/RegEx/Tests/RegExTests/NoOverlapTests.swift: 1| |// 2| |// NoOverlapTests.swift 3| |// RegExTests 4| |// 5| |// Created by Eneko Alonso on 5/18/19. 6| |// 7| | 8| |import XCTest 9| |import RegEx 10| | 11| |class NoOverlapTests: XCTestCase { 12| | 13| 1| func testNonOverlapping() throws { 14| 1| let regex = try RegEx(pattern: "aa") 15| 1| let matches = regex.matches(in: "aaaa") 16| 1| XCTAssertEqual(matches.count, 2) 17| 1| XCTAssertEqual(matches[0].values.count, 1) 18| 1| XCTAssertEqual(matches[1].values.count, 1) 19| 1| XCTAssertEqual(matches[0].values[0], "aa") 20| 1| XCTAssertEqual(matches[1].values[0], "aa") 21| 1| } 22| | 23| 1| func testNonOverlappingGroups() throws { 24| 1| let regex = try RegEx(pattern: "(aa)") 25| 1| let matches = regex.matches(in: "aaaa") 26| 1| XCTAssertEqual(matches.count, 2) 27| 1| XCTAssertEqual(matches[0].values.count, 2) 28| 1| XCTAssertEqual(matches[1].values.count, 2) 29| 1| XCTAssertEqual(matches[0].values[0], "aa") 30| 1| XCTAssertEqual(matches[0].values[1], "aa") 31| 1| XCTAssertEqual(matches[1].values[0], "aa") 32| 1| XCTAssertEqual(matches[1].values[1], "aa") 33| 1| } 34| | 35| |} /Users/travis/build/eneko/RegEx/Tests/RegExTests/ReplacementTests.swift: 1| |// 2| |// ReplacementTests.swift 3| |// RegExTests 4| |// 5| |// Created by Eneko Alonso on 5/19/19. 6| |// 7| | 8| |import XCTest 9| |import RegEx 10| | 11| |class ReplacementTests: XCTestCase { 12| | 13| | let donQuixote = """ 14| | En un lugar de la Mancha, de cuyo nombre no quiero acordarme, no ha 15| | mucho tiempo que vivía un hidalgo de los de lanza en astillero, adarga 16| | antigua, rocín flaco y galgo corredor. Una olla de algo más vaca que 17| | carnero, salpicón las más noches, duelos y quebrantos los sábados, 18| | lantejas los viernes, algún palomino de añadidura los domingos, 19| | consumían las tres cuartas partes de su hacienda. El resto della 20| | concluían sayo de velarte, calzas de velludo para las fiestas, con 21| | sus pantuflos de lo mesmo, y los días de entresemana se honraba con 22| | su vellorí de lo más fino. Tenía en su casa una ama que pasaba de 23| | los cuarenta, y una sobrina que no llegaba a los veinte, y un mozo 24| | de campo y plaza, que así ensillaba el rocín como tomaba la podadera. 25| | Frisaba la edad de nuestro hidalgo con los cincuenta años; era de 26| | complexión recia, seco de carnes, enjuto de rostro, gran madrugador y 27| | amigo de la caza. Quieren decir que tenía el sobrenombre de Quijada, 28| | o Quesada, que en esto hay alguna diferencia en los autores que deste 29| | caso escriben; aunque, por conjeturas verosímiles, se deja entender 30| | que se llamaba Quejana. Pero esto importa poco a nuestro cuento; basta 31| | que en la narración dél no se salga un punto de la verdad. 32| | """ 33| | 34| 1| func testReplaceAll() throws { 35| 1| let regex = try RegEx(pattern: #"(\w+)a\b"#) 36| 1| let output = regex.replaceMatches(in: donQuixote, withTemplate: "$1o") 37| 1| XCTAssertTrue(output.hasPrefix("En un lugar de lo Mancho")) 38| 1| } 39| | 40| 1| func testDuplicateWordsEndingInAWithTemplate() throws { 41| 1| let regex = try RegEx(pattern: #"(\w+a)\b"#) 42| 1| let output = regex.replaceMatches(in: donQuixote, withTemplate: "$1$1") 43| 1| XCTAssertTrue(output.hasPrefix("En un lugar de lala ManchaMancha")) 44| 1| } 45| | 46| 1| func testDuplicateWordsEndingInAWithCustomLogic() throws { 47| 1| let regex = try RegEx(pattern: #"(\w+a)\b"#) 48| 50| let output = regex.replaceMatches(in: donQuixote) { match in 49| 50| let value = String(match.values[0] ?? "") 50| 50| return value + value 51| 50| } 52| 1| XCTAssertTrue(output.hasPrefix("En un lugar de lala ManchaMancha")) 53| 1| } 54| | 55| 1| func testReverseWordsEndingInA() throws { 56| 1| let regex = try RegEx(pattern: #"(\w+)a\b"#) 57| 50| let output = regex.replaceMatches(in: donQuixote) { match in 58| 50| let value = String(match.values[0] ?? "") 59| 50| return String(value.reversed()) 60| 50| } 61| 1| XCTAssertTrue(output.hasPrefix("En un lugar de al ahcnaM")) 62| 1| } 63| | 64| 1| func testCapitalizeWordsEndingInA() throws { 65| 1| let regex = try RegEx(pattern: #"(\w+a)\b"#) 66| 50| let output = regex.replaceMatches(in: donQuixote) { match in 67| 50| let value = String(match.values[0] ?? "") 68| 50| return value.uppercased() 69| 50| } 70| 1| XCTAssertTrue(output.hasPrefix("En un lugar de LA MANCHA")) 71| 1| } 72| | 73| 1| func testInitializeWordsEndingInA() throws { 74| 1| let regex = try RegEx(pattern: #"(\w+a)\b"#) 75| 50| let output = regex.replaceMatches(in: donQuixote) { match in 76| 50| let value = String(match.values[0] ?? "") 77| 50| let initial = String(value[..?] 19| | } 20| | 21| 0| public func numberOfMatches(in string: String, from index: String.Index? = nil) -> Int { 22| 0| let startIndex = index ?? string.startIndex 23| 0| let range = NSRange(startIndex..., in: string) 24| 0| return regex.numberOfMatches(in: string, range: range) 25| 0| } 26| | 27| 221| public func firstMatch(in string: String, from index: String.Index? = nil) -> Match? { 28| 221| let startIndex = index ?? string.startIndex 29| 221| let range = NSRange(startIndex..., in: string) 30| 221| let result = regex.firstMatch(in: string, range: range) 31| 221| return result.flatMap { map(result: $0, in: string) } 32| 221| } 33| | 34| 14| public func matches(in string: String, from index: String.Index? = nil) -> [Match] { 35| 14| let startIndex = index ?? string.startIndex 36| 14| let range = NSRange(startIndex..., in: string) 37| 14| let results = regex.matches(in: string, range: range) 38| 18| return results.map { map(result: $0, in: string) } 39| 14| } 40| | 41| 8| public func test(_ string: String) -> Bool { 42| 8| return firstMatch(in: string) != nil 43| 8| } 44| | 45| 230| func map(result: NSTextCheckingResult, in string: String) -> Match { 46| 460| let ranges = (0.. String { 59| 3| let range = NSRange(string.startIndex..., in: string) 60| 3| return regex.stringByReplacingMatches(in: string, range: range, withTemplate: template) 61| 3| } 62| | 63| 5| public func replaceMatches(in string: String, replacement: (Match) -> String) -> String { 64| 5| var currentIndex = string.startIndex 65| 5| var output: [String] = [] 66| 5| let iterator = self.iterator(for: string) 67| 202| while let match = iterator.next(), let matchRange = match.ranges[0] { 68| 202| output.append(String(string[currentIndex.. RegEx.Match? { 92| 210| defer { 93| 210| current = current.flatMap { 94| 205| let index = $0.ranges[0]?.upperBound 95| 205| return self.regex.firstMatch(in: self.string, from: index) 96| 205| } 97| 210| } 98| 210| return current 99| 210| } 100| | } 101| | 102| 6| public func iterator(for string: String) -> Iterator { 103| 6| return Iterator(regex: self, string: string) 104| 6| } 105| |} <<<<<< EOF