├── .gitignore ├── .swift-version ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── LLRegex.playground.zip ├── LLRegex.podspec ├── Package.swift ├── Project ├── LLRegex.xcodeproj │ ├── project.pbxproj │ └── xcshareddata │ │ └── xcschemes │ │ ├── LLRegex iOS.xcscheme │ │ ├── LLRegex macOS.xcscheme │ │ ├── LLRegex tvOS.xcscheme │ │ └── LLRegex watchOS.xcscheme ├── LLRegex │ ├── Info.plist │ ├── LLRegex.h │ └── Playground.swift └── LLRegexTests │ ├── Info.plist │ └── LargeContent.txt ├── README.md ├── Sources ├── Match.swift ├── NSRange+Util.swift ├── OptionSetAdapting.swift ├── Regex.swift ├── String+Regex.swift └── String+Util.swift └── Tests └── LLRegexTests ├── EmptyPatternRegexTests.swift ├── EmptyStringRegexTests.swift ├── LLRegexTests.swift ├── NamedCaptureGroupsTests.swift ├── RegexTests.swift ├── ReturnRegexTests.swift ├── StringRegexTests.swift └── WordBRegexTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode9 3 | branches: 4 | only: 5 | - master 6 | - develop 7 | 8 | env: 9 | global: 10 | - LC_CTYPE=en_US.UTF-8 11 | - LANG=en_US.UTF-8 12 | - PROJECT="Project/LLRegex.xcodeproj" 13 | - IOS_FRAMEWORK_SCHEME="LLRegex iOS" 14 | - MACOS_FRAMEWORK_SCHEME="LLRegex macOS" 15 | - TVOS_FRAMEWORK_SCHEME="LLRegex tvOS" 16 | - WATCHOS_FRAMEWORK_SCHEME="LLRegex watchOS" 17 | - HAS_TEST="YES" 18 | matrix: 19 | - DESTINATION="OS=4.0,name=Apple Watch - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" HAS_TEST="NO" 20 | - DESTINATION="OS=3.2,name=Apple Watch - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" HAS_TEST="NO" 21 | - DESTINATION="OS=2.0,name=Apple Watch - 42mm" SCHEME="$WATCHOS_FRAMEWORK_SCHEME" HAS_TEST="NO" 22 | 23 | - DESTINATION="OS=11.0,name=iPhone 7 Plus" SCHEME="$IOS_FRAMEWORK_SCHEME" 24 | - DESTINATION="OS=10.3.1,name=iPhone 7 Plus" SCHEME="$IOS_FRAMEWORK_SCHEME" 25 | - DESTINATION="OS=9.0,name=iPhone 6" SCHEME="$IOS_FRAMEWORK_SCHEME" 26 | - DESTINATION="OS=8.1,name=iPhone 4S" SCHEME="$IOS_FRAMEWORK_SCHEME" 27 | 28 | - DESTINATION="OS=11.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" 29 | - DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" 30 | - DESTINATION="OS=9.0,name=Apple TV 1080p" SCHEME="$TVOS_FRAMEWORK_SCHEME" 31 | 32 | - DESTINATION="arch=x86_64" SCHEME="$MACOS_FRAMEWORK_SCHEME" 33 | script: 34 | - xcodebuild -version 35 | - xcodebuild -showsdks 36 | 37 | # DEBUG 38 | - if [ $HAS_TEST == "YES" ]; then 39 | xcodebuild -project "$PROJECT" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 40 | else 41 | xcodebuild -project "$PROJECT" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Debug ONLY_ACTIVE_ARCH=NO build | xcpretty; 42 | fi 43 | 44 | # RELEASE 45 | - if [ $HAS_TEST == "YES" ]; then 46 | xcodebuild -project "$PROJECT" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO ENABLE_TESTABILITY=YES test | xcpretty; 47 | else 48 | xcodebuild -project "$PROJECT" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Release ONLY_ACTIVE_ARCH=NO build | xcpretty; 49 | fi -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 1.3.0 4 | - Compatible with Swift 4.0 5 | - `CaptureGroup` conforms to `MatchProtocol` 6 | - `matched` on `CaptureGroup` became Non-optional. Empty string is returned if conversion is failed. 7 | - `range` on `Match` became Optional. `nil` is returned if conversion from NSRange is failed. 8 | - `String.split` returns `[Substring]` instead of `[String]` 9 | - Performance improved 10 | 11 | ## 1.2.1 12 | - Compatible with Swift 3.2 13 | 14 | ## 1.2.0 15 | - Named capture group 16 | - `Regex.Options` is not type alias of `NSRegularExpession.Options` any longer. 17 | - Add `Regex.Options.namedCaputreGroups` 18 | - `Match.Options` is not type alias of `NSRegularExpession.MatchingOptions` any longer. 19 | - Add `Match.Options.reportProgress` & `Match.Options.reportCompletion` 20 | - 21 | ## 1.1.1 22 | - Compatible with Swift 3.2 23 | - Swift Package Manager supported 24 | 25 | ## 1.1.0 26 | - `Regex.init`` changed - one accepts string literal, the other one accepts string may throwing error. 27 | - macOS, tvOS, watchOS supported. 28 | 29 | ## 1.0.0 30 | - LLRegex initial version -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Rock Young 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LLRegex.playground.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LittleRockInGitHub/LLRegex/fa6b145f0b6f5e336904532dcf3bcf54ca070da0/LLRegex.playground.zip -------------------------------------------------------------------------------- /LLRegex.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'LLRegex' 3 | s.version = '1.3.0' 4 | s.summary = 'Regular expression library in Swift, wrapping NSRegularExpression.' 5 | s.homepage = 'https://github.com/LittleRockInGitHub/LLRegex' 6 | s.license = { :type => 'MIT', :file => 'LICENSE' } 7 | s.author = { 'Rocke Young' => 'rockforcareer@icloud.com' } 8 | s.source = { :git => 'https://github.com/LittleRockInGitHub/LLRegex.git', :tag => s.version.to_s } 9 | s.ios.deployment_target = '8.0' 10 | s.osx.deployment_target = '10.10' 11 | s.tvos.deployment_target = '9.0' 12 | s.watchos.deployment_target = '2.0' 13 | 14 | s.source_files = 'Sources/*.swift' 15 | end 16 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "LLRegex" 5 | ) 6 | -------------------------------------------------------------------------------- /Project/LLRegex.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9D31D56D1EF285DF0002DDA0 /* LargeContent.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9D31D56C1EF285DF0002DDA0 /* LargeContent.txt */; }; 11 | 9D31D56E1EF285DF0002DDA0 /* LargeContent.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9D31D56C1EF285DF0002DDA0 /* LargeContent.txt */; }; 12 | 9D31D56F1EF285DF0002DDA0 /* LargeContent.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9D31D56C1EF285DF0002DDA0 /* LargeContent.txt */; }; 13 | 9D7656DC1EEBF1D100016136 /* LLRegex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D7656D31EEBF1D000016136 /* LLRegex.framework */; }; 14 | 9D7656EA1EEBF2E700016136 /* LLRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15 | 9D7657231EEC4E8000016136 /* LLRegex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D76571A1EEC4E8000016136 /* LLRegex.framework */; }; 16 | 9D7657361EEC4F7B00016136 /* LLRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 17 | 9D76574B1EEC50FF00016136 /* LLRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 18 | 9D9682951EF2A6C5004307E2 /* NSRange+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */; }; 19 | 9D9682961EF2A6C5004307E2 /* NSRange+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */; }; 20 | 9D9682971EF2A6C5004307E2 /* NSRange+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */; }; 21 | 9D9682981EF2A6C5004307E2 /* NSRange+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */; }; 22 | 9D9682991EF2A6C5004307E2 /* String+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682941EF2A6C5004307E2 /* String+Util.swift */; }; 23 | 9D96829A1EF2A6C5004307E2 /* String+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682941EF2A6C5004307E2 /* String+Util.swift */; }; 24 | 9D96829B1EF2A6C5004307E2 /* String+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682941EF2A6C5004307E2 /* String+Util.swift */; }; 25 | 9D96829C1EF2A6C5004307E2 /* String+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682941EF2A6C5004307E2 /* String+Util.swift */; }; 26 | 9D9682A01EF2A6D4004307E2 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829D1EF2A6D4004307E2 /* Match.swift */; }; 27 | 9D9682A11EF2A6D4004307E2 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829D1EF2A6D4004307E2 /* Match.swift */; }; 28 | 9D9682A21EF2A6D4004307E2 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829D1EF2A6D4004307E2 /* Match.swift */; }; 29 | 9D9682A31EF2A6D4004307E2 /* Match.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829D1EF2A6D4004307E2 /* Match.swift */; }; 30 | 9D9682A41EF2A6D4004307E2 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829E1EF2A6D4004307E2 /* Regex.swift */; }; 31 | 9D9682A51EF2A6D4004307E2 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829E1EF2A6D4004307E2 /* Regex.swift */; }; 32 | 9D9682A61EF2A6D4004307E2 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829E1EF2A6D4004307E2 /* Regex.swift */; }; 33 | 9D9682A71EF2A6D4004307E2 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829E1EF2A6D4004307E2 /* Regex.swift */; }; 34 | 9D9682A81EF2A6D4004307E2 /* String+Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */; }; 35 | 9D9682A91EF2A6D4004307E2 /* String+Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */; }; 36 | 9D9682AA1EF2A6D4004307E2 /* String+Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */; }; 37 | 9D9682AB1EF2A6D4004307E2 /* String+Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */; }; 38 | 9D9682B31EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AC1EF2A726004307E2 /* EmptyPatternRegexTests.swift */; }; 39 | 9D9682B41EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AC1EF2A726004307E2 /* EmptyPatternRegexTests.swift */; }; 40 | 9D9682B51EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AC1EF2A726004307E2 /* EmptyPatternRegexTests.swift */; }; 41 | 9D9682B61EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AD1EF2A726004307E2 /* EmptyStringRegexTests.swift */; }; 42 | 9D9682B71EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AD1EF2A726004307E2 /* EmptyStringRegexTests.swift */; }; 43 | 9D9682B81EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AD1EF2A726004307E2 /* EmptyStringRegexTests.swift */; }; 44 | 9D9682B91EF2A726004307E2 /* LLRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AE1EF2A726004307E2 /* LLRegexTests.swift */; }; 45 | 9D9682BA1EF2A726004307E2 /* LLRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AE1EF2A726004307E2 /* LLRegexTests.swift */; }; 46 | 9D9682BB1EF2A726004307E2 /* LLRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AE1EF2A726004307E2 /* LLRegexTests.swift */; }; 47 | 9D9682BC1EF2A726004307E2 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AF1EF2A726004307E2 /* RegexTests.swift */; }; 48 | 9D9682BD1EF2A726004307E2 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AF1EF2A726004307E2 /* RegexTests.swift */; }; 49 | 9D9682BE1EF2A726004307E2 /* RegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682AF1EF2A726004307E2 /* RegexTests.swift */; }; 50 | 9D9682BF1EF2A726004307E2 /* ReturnRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B01EF2A726004307E2 /* ReturnRegexTests.swift */; }; 51 | 9D9682C01EF2A726004307E2 /* ReturnRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B01EF2A726004307E2 /* ReturnRegexTests.swift */; }; 52 | 9D9682C11EF2A726004307E2 /* ReturnRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B01EF2A726004307E2 /* ReturnRegexTests.swift */; }; 53 | 9D9682C21EF2A726004307E2 /* StringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B11EF2A726004307E2 /* StringRegexTests.swift */; }; 54 | 9D9682C31EF2A726004307E2 /* StringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B11EF2A726004307E2 /* StringRegexTests.swift */; }; 55 | 9D9682C41EF2A726004307E2 /* StringRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B11EF2A726004307E2 /* StringRegexTests.swift */; }; 56 | 9D9682C51EF2A726004307E2 /* WordBRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B21EF2A726004307E2 /* WordBRegexTests.swift */; }; 57 | 9D9682C61EF2A726004307E2 /* WordBRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B21EF2A726004307E2 /* WordBRegexTests.swift */; }; 58 | 9D9682C71EF2A726004307E2 /* WordBRegexTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D9682B21EF2A726004307E2 /* WordBRegexTests.swift */; }; 59 | 9DD5D05F1EEAB3EB009CAE13 /* LLRegex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9DD5D0551EEAB3EB009CAE13 /* LLRegex.framework */; }; 60 | 9DD5D0661EEAB3EB009CAE13 /* LLRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 61 | 9DE5C8C11EFA85B500E1914B /* NamedCaptureGroupsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C01EFA85B500E1914B /* NamedCaptureGroupsTests.swift */; }; 62 | 9DE5C8C21EFA85B800E1914B /* NamedCaptureGroupsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C01EFA85B500E1914B /* NamedCaptureGroupsTests.swift */; }; 63 | 9DE5C8C31EFA85BA00E1914B /* NamedCaptureGroupsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C01EFA85B500E1914B /* NamedCaptureGroupsTests.swift */; }; 64 | 9DE5C8C51EFAD7FF00E1914B /* OptionSetAdapting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */; }; 65 | 9DE5C8C61EFBC94500E1914B /* OptionSetAdapting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */; }; 66 | 9DE5C8C71EFBC94600E1914B /* OptionSetAdapting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */; }; 67 | 9DE5C8C81EFBC94700E1914B /* OptionSetAdapting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */; }; 68 | /* End PBXBuildFile section */ 69 | 70 | /* Begin PBXContainerItemProxy section */ 71 | 9D7656DD1EEBF1D100016136 /* PBXContainerItemProxy */ = { 72 | isa = PBXContainerItemProxy; 73 | containerPortal = 9DD5D04C1EEAB3EB009CAE13 /* Project object */; 74 | proxyType = 1; 75 | remoteGlobalIDString = 9D7656D21EEBF1D000016136; 76 | remoteInfo = "LLRegex macOS"; 77 | }; 78 | 9D7657241EEC4E8000016136 /* PBXContainerItemProxy */ = { 79 | isa = PBXContainerItemProxy; 80 | containerPortal = 9DD5D04C1EEAB3EB009CAE13 /* Project object */; 81 | proxyType = 1; 82 | remoteGlobalIDString = 9D7657191EEC4E8000016136; 83 | remoteInfo = "LLRegex tvOS"; 84 | }; 85 | 9DD5D0601EEAB3EB009CAE13 /* PBXContainerItemProxy */ = { 86 | isa = PBXContainerItemProxy; 87 | containerPortal = 9DD5D04C1EEAB3EB009CAE13 /* Project object */; 88 | proxyType = 1; 89 | remoteGlobalIDString = 9DD5D0541EEAB3EB009CAE13; 90 | remoteInfo = LLRegex; 91 | }; 92 | /* End PBXContainerItemProxy section */ 93 | 94 | /* Begin PBXFileReference section */ 95 | 9D31D56C1EF285DF0002DDA0 /* LargeContent.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LargeContent.txt; sourceTree = ""; }; 96 | 9D7656D31EEBF1D000016136 /* LLRegex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLRegex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | 9D7656DB1EEBF1D100016136 /* LLRegex macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LLRegex macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | 9D76571A1EEC4E8000016136 /* LLRegex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLRegex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 99 | 9D7657221EEC4E8000016136 /* LLRegex tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LLRegex tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 100 | 9D7657431EEC509A00016136 /* LLRegex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLRegex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 101 | 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSRange+Util.swift"; path = "../../Sources/NSRange+Util.swift"; sourceTree = ""; }; 102 | 9D9682941EF2A6C5004307E2 /* String+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+Util.swift"; path = "../../Sources/String+Util.swift"; sourceTree = ""; }; 103 | 9D96829D1EF2A6D4004307E2 /* Match.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Match.swift; path = ../../Sources/Match.swift; sourceTree = ""; }; 104 | 9D96829E1EF2A6D4004307E2 /* Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Regex.swift; path = ../../Sources/Regex.swift; sourceTree = ""; }; 105 | 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "String+Regex.swift"; path = "../../Sources/String+Regex.swift"; sourceTree = ""; }; 106 | 9D9682AC1EF2A726004307E2 /* EmptyPatternRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EmptyPatternRegexTests.swift; path = ../../Tests/LLRegexTests/EmptyPatternRegexTests.swift; sourceTree = ""; }; 107 | 9D9682AD1EF2A726004307E2 /* EmptyStringRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EmptyStringRegexTests.swift; path = ../../Tests/LLRegexTests/EmptyStringRegexTests.swift; sourceTree = ""; }; 108 | 9D9682AE1EF2A726004307E2 /* LLRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LLRegexTests.swift; path = ../../Tests/LLRegexTests/LLRegexTests.swift; sourceTree = ""; }; 109 | 9D9682AF1EF2A726004307E2 /* RegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RegexTests.swift; path = ../../Tests/LLRegexTests/RegexTests.swift; sourceTree = ""; }; 110 | 9D9682B01EF2A726004307E2 /* ReturnRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ReturnRegexTests.swift; path = ../../Tests/LLRegexTests/ReturnRegexTests.swift; sourceTree = ""; }; 111 | 9D9682B11EF2A726004307E2 /* StringRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StringRegexTests.swift; path = ../../Tests/LLRegexTests/StringRegexTests.swift; sourceTree = ""; }; 112 | 9D9682B21EF2A726004307E2 /* WordBRegexTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WordBRegexTests.swift; path = ../../Tests/LLRegexTests/WordBRegexTests.swift; sourceTree = ""; }; 113 | 9DD5D0551EEAB3EB009CAE13 /* LLRegex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LLRegex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 114 | 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LLRegex.h; sourceTree = ""; }; 115 | 9DD5D0591EEAB3EB009CAE13 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 116 | 9DD5D05E1EEAB3EB009CAE13 /* LLRegex iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LLRegex iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 117 | 9DD5D0651EEAB3EB009CAE13 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 118 | 9DE5C8C01EFA85B500E1914B /* NamedCaptureGroupsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NamedCaptureGroupsTests.swift; path = ../../Tests/LLRegexTests/NamedCaptureGroupsTests.swift; sourceTree = ""; }; 119 | 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OptionSetAdapting.swift; path = ../../Sources/OptionSetAdapting.swift; sourceTree = ""; }; 120 | /* End PBXFileReference section */ 121 | 122 | /* Begin PBXFrameworksBuildPhase section */ 123 | 9D7656CF1EEBF1D000016136 /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | 9D7656D81EEBF1D100016136 /* Frameworks */ = { 131 | isa = PBXFrameworksBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | 9D7656DC1EEBF1D100016136 /* LLRegex.framework in Frameworks */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | 9D7657161EEC4E8000016136 /* Frameworks */ = { 139 | isa = PBXFrameworksBuildPhase; 140 | buildActionMask = 2147483647; 141 | files = ( 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | 9D76571F1EEC4E8000016136 /* Frameworks */ = { 146 | isa = PBXFrameworksBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 9D7657231EEC4E8000016136 /* LLRegex.framework in Frameworks */, 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | }; 153 | 9D76573F1EEC509A00016136 /* Frameworks */ = { 154 | isa = PBXFrameworksBuildPhase; 155 | buildActionMask = 2147483647; 156 | files = ( 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | 9DD5D0511EEAB3EB009CAE13 /* Frameworks */ = { 161 | isa = PBXFrameworksBuildPhase; 162 | buildActionMask = 2147483647; 163 | files = ( 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | 9DD5D05B1EEAB3EB009CAE13 /* Frameworks */ = { 168 | isa = PBXFrameworksBuildPhase; 169 | buildActionMask = 2147483647; 170 | files = ( 171 | 9DD5D05F1EEAB3EB009CAE13 /* LLRegex.framework in Frameworks */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXFrameworksBuildPhase section */ 176 | 177 | /* Begin PBXGroup section */ 178 | 9DD5D04B1EEAB3EB009CAE13 = { 179 | isa = PBXGroup; 180 | children = ( 181 | 9DD5D0571EEAB3EB009CAE13 /* LLRegex */, 182 | 9DD5D0621EEAB3EB009CAE13 /* LLRegexTests */, 183 | 9DD5D0561EEAB3EB009CAE13 /* Products */, 184 | ); 185 | sourceTree = ""; 186 | }; 187 | 9DD5D0561EEAB3EB009CAE13 /* Products */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 9DD5D0551EEAB3EB009CAE13 /* LLRegex.framework */, 191 | 9DD5D05E1EEAB3EB009CAE13 /* LLRegex iOS Tests.xctest */, 192 | 9D7656D31EEBF1D000016136 /* LLRegex.framework */, 193 | 9D7656DB1EEBF1D100016136 /* LLRegex macOS Tests.xctest */, 194 | 9D76571A1EEC4E8000016136 /* LLRegex.framework */, 195 | 9D7657221EEC4E8000016136 /* LLRegex tvOS Tests.xctest */, 196 | 9D7657431EEC509A00016136 /* LLRegex.framework */, 197 | ); 198 | name = Products; 199 | sourceTree = ""; 200 | }; 201 | 9DD5D0571EEAB3EB009CAE13 /* LLRegex */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | 9D96829E1EF2A6D4004307E2 /* Regex.swift */, 205 | 9D96829D1EF2A6D4004307E2 /* Match.swift */, 206 | 9D96829F1EF2A6D4004307E2 /* String+Regex.swift */, 207 | 9DD5D0791EEAB484009CAE13 /* Utility */, 208 | 9DF71B4D1EEFD77D0049EF54 /* Supporting Files */, 209 | ); 210 | path = LLRegex; 211 | sourceTree = ""; 212 | }; 213 | 9DD5D0621EEAB3EB009CAE13 /* LLRegexTests */ = { 214 | isa = PBXGroup; 215 | children = ( 216 | 9D9682AE1EF2A726004307E2 /* LLRegexTests.swift */, 217 | 9DE5C8C01EFA85B500E1914B /* NamedCaptureGroupsTests.swift */, 218 | 9D9682B11EF2A726004307E2 /* StringRegexTests.swift */, 219 | 9D9682AF1EF2A726004307E2 /* RegexTests.swift */, 220 | 9D9682AC1EF2A726004307E2 /* EmptyPatternRegexTests.swift */, 221 | 9D9682AD1EF2A726004307E2 /* EmptyStringRegexTests.swift */, 222 | 9D9682B01EF2A726004307E2 /* ReturnRegexTests.swift */, 223 | 9D9682B21EF2A726004307E2 /* WordBRegexTests.swift */, 224 | 9D31D56C1EF285DF0002DDA0 /* LargeContent.txt */, 225 | 9DD5D0651EEAB3EB009CAE13 /* Info.plist */, 226 | ); 227 | path = LLRegexTests; 228 | sourceTree = ""; 229 | }; 230 | 9DD5D0791EEAB484009CAE13 /* Utility */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 9D9682931EF2A6C5004307E2 /* NSRange+Util.swift */, 234 | 9D9682941EF2A6C5004307E2 /* String+Util.swift */, 235 | 9DE5C8C41EFAD7FF00E1914B /* OptionSetAdapting.swift */, 236 | ); 237 | name = Utility; 238 | sourceTree = ""; 239 | }; 240 | 9DF71B4D1EEFD77D0049EF54 /* Supporting Files */ = { 241 | isa = PBXGroup; 242 | children = ( 243 | 9DD5D0581EEAB3EB009CAE13 /* LLRegex.h */, 244 | 9DD5D0591EEAB3EB009CAE13 /* Info.plist */, 245 | ); 246 | name = "Supporting Files"; 247 | sourceTree = ""; 248 | }; 249 | /* End PBXGroup section */ 250 | 251 | /* Begin PBXHeadersBuildPhase section */ 252 | 9D7656D01EEBF1D000016136 /* Headers */ = { 253 | isa = PBXHeadersBuildPhase; 254 | buildActionMask = 2147483647; 255 | files = ( 256 | 9D7656EA1EEBF2E700016136 /* LLRegex.h in Headers */, 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | 9D7657171EEC4E8000016136 /* Headers */ = { 261 | isa = PBXHeadersBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | 9D7657361EEC4F7B00016136 /* LLRegex.h in Headers */, 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | }; 268 | 9D7657401EEC509A00016136 /* Headers */ = { 269 | isa = PBXHeadersBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | 9D76574B1EEC50FF00016136 /* LLRegex.h in Headers */, 273 | ); 274 | runOnlyForDeploymentPostprocessing = 0; 275 | }; 276 | 9DD5D0521EEAB3EB009CAE13 /* Headers */ = { 277 | isa = PBXHeadersBuildPhase; 278 | buildActionMask = 2147483647; 279 | files = ( 280 | 9DD5D0661EEAB3EB009CAE13 /* LLRegex.h in Headers */, 281 | ); 282 | runOnlyForDeploymentPostprocessing = 0; 283 | }; 284 | /* End PBXHeadersBuildPhase section */ 285 | 286 | /* Begin PBXNativeTarget section */ 287 | 9D7656D21EEBF1D000016136 /* LLRegex macOS */ = { 288 | isa = PBXNativeTarget; 289 | buildConfigurationList = 9D7656E81EEBF1D100016136 /* Build configuration list for PBXNativeTarget "LLRegex macOS" */; 290 | buildPhases = ( 291 | 9D7656CE1EEBF1D000016136 /* Sources */, 292 | 9D7656CF1EEBF1D000016136 /* Frameworks */, 293 | 9D7656D01EEBF1D000016136 /* Headers */, 294 | 9D7656D11EEBF1D000016136 /* Resources */, 295 | ); 296 | buildRules = ( 297 | ); 298 | dependencies = ( 299 | ); 300 | name = "LLRegex macOS"; 301 | productName = "LLRegex macOS"; 302 | productReference = 9D7656D31EEBF1D000016136 /* LLRegex.framework */; 303 | productType = "com.apple.product-type.framework"; 304 | }; 305 | 9D7656DA1EEBF1D100016136 /* LLRegex macOS Tests */ = { 306 | isa = PBXNativeTarget; 307 | buildConfigurationList = 9D7656E91EEBF1D100016136 /* Build configuration list for PBXNativeTarget "LLRegex macOS Tests" */; 308 | buildPhases = ( 309 | 9D7656D71EEBF1D100016136 /* Sources */, 310 | 9D7656D81EEBF1D100016136 /* Frameworks */, 311 | 9D7656D91EEBF1D100016136 /* Resources */, 312 | ); 313 | buildRules = ( 314 | ); 315 | dependencies = ( 316 | 9D7656DE1EEBF1D100016136 /* PBXTargetDependency */, 317 | ); 318 | name = "LLRegex macOS Tests"; 319 | productName = "LLRegex macOSTests"; 320 | productReference = 9D7656DB1EEBF1D100016136 /* LLRegex macOS Tests.xctest */; 321 | productType = "com.apple.product-type.bundle.unit-test"; 322 | }; 323 | 9D7657191EEC4E8000016136 /* LLRegex tvOS */ = { 324 | isa = PBXNativeTarget; 325 | buildConfigurationList = 9D76572F1EEC4E8000016136 /* Build configuration list for PBXNativeTarget "LLRegex tvOS" */; 326 | buildPhases = ( 327 | 9D7657151EEC4E8000016136 /* Sources */, 328 | 9D7657161EEC4E8000016136 /* Frameworks */, 329 | 9D7657171EEC4E8000016136 /* Headers */, 330 | 9D7657181EEC4E8000016136 /* Resources */, 331 | ); 332 | buildRules = ( 333 | ); 334 | dependencies = ( 335 | ); 336 | name = "LLRegex tvOS"; 337 | productName = "LLRegex tvOS"; 338 | productReference = 9D76571A1EEC4E8000016136 /* LLRegex.framework */; 339 | productType = "com.apple.product-type.framework"; 340 | }; 341 | 9D7657211EEC4E8000016136 /* LLRegex tvOS Tests */ = { 342 | isa = PBXNativeTarget; 343 | buildConfigurationList = 9D7657301EEC4E8000016136 /* Build configuration list for PBXNativeTarget "LLRegex tvOS Tests" */; 344 | buildPhases = ( 345 | 9D76571E1EEC4E8000016136 /* Sources */, 346 | 9D76571F1EEC4E8000016136 /* Frameworks */, 347 | 9D7657201EEC4E8000016136 /* Resources */, 348 | ); 349 | buildRules = ( 350 | ); 351 | dependencies = ( 352 | 9D7657251EEC4E8000016136 /* PBXTargetDependency */, 353 | ); 354 | name = "LLRegex tvOS Tests"; 355 | productName = "LLRegex tvOSTests"; 356 | productReference = 9D7657221EEC4E8000016136 /* LLRegex tvOS Tests.xctest */; 357 | productType = "com.apple.product-type.bundle.unit-test"; 358 | }; 359 | 9D7657421EEC509A00016136 /* LLRegex watchOS */ = { 360 | isa = PBXNativeTarget; 361 | buildConfigurationList = 9D7657481EEC509A00016136 /* Build configuration list for PBXNativeTarget "LLRegex watchOS" */; 362 | buildPhases = ( 363 | 9D76573E1EEC509A00016136 /* Sources */, 364 | 9D76573F1EEC509A00016136 /* Frameworks */, 365 | 9D7657401EEC509A00016136 /* Headers */, 366 | 9D7657411EEC509A00016136 /* Resources */, 367 | ); 368 | buildRules = ( 369 | ); 370 | dependencies = ( 371 | ); 372 | name = "LLRegex watchOS"; 373 | productName = "LLRegex watchOS"; 374 | productReference = 9D7657431EEC509A00016136 /* LLRegex.framework */; 375 | productType = "com.apple.product-type.framework"; 376 | }; 377 | 9DD5D0541EEAB3EB009CAE13 /* LLRegex iOS */ = { 378 | isa = PBXNativeTarget; 379 | buildConfigurationList = 9DD5D0691EEAB3EB009CAE13 /* Build configuration list for PBXNativeTarget "LLRegex iOS" */; 380 | buildPhases = ( 381 | 9DD5D0501EEAB3EB009CAE13 /* Sources */, 382 | 9DD5D0511EEAB3EB009CAE13 /* Frameworks */, 383 | 9DD5D0521EEAB3EB009CAE13 /* Headers */, 384 | 9DD5D0531EEAB3EB009CAE13 /* Resources */, 385 | ); 386 | buildRules = ( 387 | ); 388 | dependencies = ( 389 | ); 390 | name = "LLRegex iOS"; 391 | productName = LLRegex; 392 | productReference = 9DD5D0551EEAB3EB009CAE13 /* LLRegex.framework */; 393 | productType = "com.apple.product-type.framework"; 394 | }; 395 | 9DD5D05D1EEAB3EB009CAE13 /* LLRegex iOS Tests */ = { 396 | isa = PBXNativeTarget; 397 | buildConfigurationList = 9DD5D06C1EEAB3EB009CAE13 /* Build configuration list for PBXNativeTarget "LLRegex iOS Tests" */; 398 | buildPhases = ( 399 | 9DD5D05A1EEAB3EB009CAE13 /* Sources */, 400 | 9DD5D05B1EEAB3EB009CAE13 /* Frameworks */, 401 | 9DD5D05C1EEAB3EB009CAE13 /* Resources */, 402 | ); 403 | buildRules = ( 404 | ); 405 | dependencies = ( 406 | 9DD5D0611EEAB3EB009CAE13 /* PBXTargetDependency */, 407 | ); 408 | name = "LLRegex iOS Tests"; 409 | productName = LLRegexTests; 410 | productReference = 9DD5D05E1EEAB3EB009CAE13 /* LLRegex iOS Tests.xctest */; 411 | productType = "com.apple.product-type.bundle.unit-test"; 412 | }; 413 | /* End PBXNativeTarget section */ 414 | 415 | /* Begin PBXProject section */ 416 | 9DD5D04C1EEAB3EB009CAE13 /* Project object */ = { 417 | isa = PBXProject; 418 | attributes = { 419 | LastSwiftUpdateCheck = 0830; 420 | LastUpgradeCheck = 0900; 421 | ORGANIZATIONNAME = "Rock Young"; 422 | TargetAttributes = { 423 | 9D7656D21EEBF1D000016136 = { 424 | CreatedOnToolsVersion = 8.3.3; 425 | LastSwiftMigration = 0900; 426 | ProvisioningStyle = Manual; 427 | }; 428 | 9D7656DA1EEBF1D100016136 = { 429 | CreatedOnToolsVersion = 8.3.3; 430 | DevelopmentTeam = 6F3LJ4NQ2D; 431 | LastSwiftMigration = 0830; 432 | ProvisioningStyle = Automatic; 433 | }; 434 | 9D7657191EEC4E8000016136 = { 435 | CreatedOnToolsVersion = 8.3.3; 436 | LastSwiftMigration = 0900; 437 | ProvisioningStyle = Manual; 438 | }; 439 | 9D7657211EEC4E8000016136 = { 440 | CreatedOnToolsVersion = 8.3.3; 441 | LastSwiftMigration = 0900; 442 | ProvisioningStyle = Manual; 443 | }; 444 | 9D7657421EEC509A00016136 = { 445 | CreatedOnToolsVersion = 8.3.3; 446 | LastSwiftMigration = 0900; 447 | ProvisioningStyle = Manual; 448 | }; 449 | 9DD5D0541EEAB3EB009CAE13 = { 450 | CreatedOnToolsVersion = 8.3.3; 451 | LastSwiftMigration = 0900; 452 | ProvisioningStyle = Manual; 453 | }; 454 | 9DD5D05D1EEAB3EB009CAE13 = { 455 | CreatedOnToolsVersion = 8.3.3; 456 | LastSwiftMigration = 0900; 457 | ProvisioningStyle = Manual; 458 | }; 459 | }; 460 | }; 461 | buildConfigurationList = 9DD5D04F1EEAB3EB009CAE13 /* Build configuration list for PBXProject "LLRegex" */; 462 | compatibilityVersion = "Xcode 3.2"; 463 | developmentRegion = English; 464 | hasScannedForEncodings = 0; 465 | knownRegions = ( 466 | en, 467 | ); 468 | mainGroup = 9DD5D04B1EEAB3EB009CAE13; 469 | productRefGroup = 9DD5D0561EEAB3EB009CAE13 /* Products */; 470 | projectDirPath = ""; 471 | projectRoot = ""; 472 | targets = ( 473 | 9DD5D0541EEAB3EB009CAE13 /* LLRegex iOS */, 474 | 9DD5D05D1EEAB3EB009CAE13 /* LLRegex iOS Tests */, 475 | 9D7656D21EEBF1D000016136 /* LLRegex macOS */, 476 | 9D7656DA1EEBF1D100016136 /* LLRegex macOS Tests */, 477 | 9D7657191EEC4E8000016136 /* LLRegex tvOS */, 478 | 9D7657211EEC4E8000016136 /* LLRegex tvOS Tests */, 479 | 9D7657421EEC509A00016136 /* LLRegex watchOS */, 480 | ); 481 | }; 482 | /* End PBXProject section */ 483 | 484 | /* Begin PBXResourcesBuildPhase section */ 485 | 9D7656D11EEBF1D000016136 /* Resources */ = { 486 | isa = PBXResourcesBuildPhase; 487 | buildActionMask = 2147483647; 488 | files = ( 489 | ); 490 | runOnlyForDeploymentPostprocessing = 0; 491 | }; 492 | 9D7656D91EEBF1D100016136 /* Resources */ = { 493 | isa = PBXResourcesBuildPhase; 494 | buildActionMask = 2147483647; 495 | files = ( 496 | 9D31D56E1EF285DF0002DDA0 /* LargeContent.txt in Resources */, 497 | ); 498 | runOnlyForDeploymentPostprocessing = 0; 499 | }; 500 | 9D7657181EEC4E8000016136 /* Resources */ = { 501 | isa = PBXResourcesBuildPhase; 502 | buildActionMask = 2147483647; 503 | files = ( 504 | ); 505 | runOnlyForDeploymentPostprocessing = 0; 506 | }; 507 | 9D7657201EEC4E8000016136 /* Resources */ = { 508 | isa = PBXResourcesBuildPhase; 509 | buildActionMask = 2147483647; 510 | files = ( 511 | 9D31D56F1EF285DF0002DDA0 /* LargeContent.txt in Resources */, 512 | ); 513 | runOnlyForDeploymentPostprocessing = 0; 514 | }; 515 | 9D7657411EEC509A00016136 /* Resources */ = { 516 | isa = PBXResourcesBuildPhase; 517 | buildActionMask = 2147483647; 518 | files = ( 519 | ); 520 | runOnlyForDeploymentPostprocessing = 0; 521 | }; 522 | 9DD5D0531EEAB3EB009CAE13 /* Resources */ = { 523 | isa = PBXResourcesBuildPhase; 524 | buildActionMask = 2147483647; 525 | files = ( 526 | ); 527 | runOnlyForDeploymentPostprocessing = 0; 528 | }; 529 | 9DD5D05C1EEAB3EB009CAE13 /* Resources */ = { 530 | isa = PBXResourcesBuildPhase; 531 | buildActionMask = 2147483647; 532 | files = ( 533 | 9D31D56D1EF285DF0002DDA0 /* LargeContent.txt in Resources */, 534 | ); 535 | runOnlyForDeploymentPostprocessing = 0; 536 | }; 537 | /* End PBXResourcesBuildPhase section */ 538 | 539 | /* Begin PBXSourcesBuildPhase section */ 540 | 9D7656CE1EEBF1D000016136 /* Sources */ = { 541 | isa = PBXSourcesBuildPhase; 542 | buildActionMask = 2147483647; 543 | files = ( 544 | 9D96829A1EF2A6C5004307E2 /* String+Util.swift in Sources */, 545 | 9DE5C8C61EFBC94500E1914B /* OptionSetAdapting.swift in Sources */, 546 | 9D9682A91EF2A6D4004307E2 /* String+Regex.swift in Sources */, 547 | 9D9682A51EF2A6D4004307E2 /* Regex.swift in Sources */, 548 | 9D9682961EF2A6C5004307E2 /* NSRange+Util.swift in Sources */, 549 | 9D9682A11EF2A6D4004307E2 /* Match.swift in Sources */, 550 | ); 551 | runOnlyForDeploymentPostprocessing = 0; 552 | }; 553 | 9D7656D71EEBF1D100016136 /* Sources */ = { 554 | isa = PBXSourcesBuildPhase; 555 | buildActionMask = 2147483647; 556 | files = ( 557 | 9D9682C61EF2A726004307E2 /* WordBRegexTests.swift in Sources */, 558 | 9D9682BA1EF2A726004307E2 /* LLRegexTests.swift in Sources */, 559 | 9D9682BD1EF2A726004307E2 /* RegexTests.swift in Sources */, 560 | 9D9682B71EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */, 561 | 9DE5C8C21EFA85B800E1914B /* NamedCaptureGroupsTests.swift in Sources */, 562 | 9D9682B41EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */, 563 | 9D9682C31EF2A726004307E2 /* StringRegexTests.swift in Sources */, 564 | 9D9682C01EF2A726004307E2 /* ReturnRegexTests.swift in Sources */, 565 | ); 566 | runOnlyForDeploymentPostprocessing = 0; 567 | }; 568 | 9D7657151EEC4E8000016136 /* Sources */ = { 569 | isa = PBXSourcesBuildPhase; 570 | buildActionMask = 2147483647; 571 | files = ( 572 | 9D96829B1EF2A6C5004307E2 /* String+Util.swift in Sources */, 573 | 9DE5C8C71EFBC94600E1914B /* OptionSetAdapting.swift in Sources */, 574 | 9D9682AA1EF2A6D4004307E2 /* String+Regex.swift in Sources */, 575 | 9D9682A61EF2A6D4004307E2 /* Regex.swift in Sources */, 576 | 9D9682971EF2A6C5004307E2 /* NSRange+Util.swift in Sources */, 577 | 9D9682A21EF2A6D4004307E2 /* Match.swift in Sources */, 578 | ); 579 | runOnlyForDeploymentPostprocessing = 0; 580 | }; 581 | 9D76571E1EEC4E8000016136 /* Sources */ = { 582 | isa = PBXSourcesBuildPhase; 583 | buildActionMask = 2147483647; 584 | files = ( 585 | 9D9682C71EF2A726004307E2 /* WordBRegexTests.swift in Sources */, 586 | 9D9682BB1EF2A726004307E2 /* LLRegexTests.swift in Sources */, 587 | 9D9682BE1EF2A726004307E2 /* RegexTests.swift in Sources */, 588 | 9D9682B81EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */, 589 | 9DE5C8C31EFA85BA00E1914B /* NamedCaptureGroupsTests.swift in Sources */, 590 | 9D9682B51EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */, 591 | 9D9682C41EF2A726004307E2 /* StringRegexTests.swift in Sources */, 592 | 9D9682C11EF2A726004307E2 /* ReturnRegexTests.swift in Sources */, 593 | ); 594 | runOnlyForDeploymentPostprocessing = 0; 595 | }; 596 | 9D76573E1EEC509A00016136 /* Sources */ = { 597 | isa = PBXSourcesBuildPhase; 598 | buildActionMask = 2147483647; 599 | files = ( 600 | 9D96829C1EF2A6C5004307E2 /* String+Util.swift in Sources */, 601 | 9DE5C8C81EFBC94700E1914B /* OptionSetAdapting.swift in Sources */, 602 | 9D9682AB1EF2A6D4004307E2 /* String+Regex.swift in Sources */, 603 | 9D9682A71EF2A6D4004307E2 /* Regex.swift in Sources */, 604 | 9D9682981EF2A6C5004307E2 /* NSRange+Util.swift in Sources */, 605 | 9D9682A31EF2A6D4004307E2 /* Match.swift in Sources */, 606 | ); 607 | runOnlyForDeploymentPostprocessing = 0; 608 | }; 609 | 9DD5D0501EEAB3EB009CAE13 /* Sources */ = { 610 | isa = PBXSourcesBuildPhase; 611 | buildActionMask = 2147483647; 612 | files = ( 613 | 9D9682991EF2A6C5004307E2 /* String+Util.swift in Sources */, 614 | 9DE5C8C51EFAD7FF00E1914B /* OptionSetAdapting.swift in Sources */, 615 | 9D9682A81EF2A6D4004307E2 /* String+Regex.swift in Sources */, 616 | 9D9682A41EF2A6D4004307E2 /* Regex.swift in Sources */, 617 | 9D9682951EF2A6C5004307E2 /* NSRange+Util.swift in Sources */, 618 | 9D9682A01EF2A6D4004307E2 /* Match.swift in Sources */, 619 | ); 620 | runOnlyForDeploymentPostprocessing = 0; 621 | }; 622 | 9DD5D05A1EEAB3EB009CAE13 /* Sources */ = { 623 | isa = PBXSourcesBuildPhase; 624 | buildActionMask = 2147483647; 625 | files = ( 626 | 9D9682C51EF2A726004307E2 /* WordBRegexTests.swift in Sources */, 627 | 9D9682B91EF2A726004307E2 /* LLRegexTests.swift in Sources */, 628 | 9D9682BC1EF2A726004307E2 /* RegexTests.swift in Sources */, 629 | 9D9682B61EF2A726004307E2 /* EmptyStringRegexTests.swift in Sources */, 630 | 9DE5C8C11EFA85B500E1914B /* NamedCaptureGroupsTests.swift in Sources */, 631 | 9D9682B31EF2A726004307E2 /* EmptyPatternRegexTests.swift in Sources */, 632 | 9D9682C21EF2A726004307E2 /* StringRegexTests.swift in Sources */, 633 | 9D9682BF1EF2A726004307E2 /* ReturnRegexTests.swift in Sources */, 634 | ); 635 | runOnlyForDeploymentPostprocessing = 0; 636 | }; 637 | /* End PBXSourcesBuildPhase section */ 638 | 639 | /* Begin PBXTargetDependency section */ 640 | 9D7656DE1EEBF1D100016136 /* PBXTargetDependency */ = { 641 | isa = PBXTargetDependency; 642 | target = 9D7656D21EEBF1D000016136 /* LLRegex macOS */; 643 | targetProxy = 9D7656DD1EEBF1D100016136 /* PBXContainerItemProxy */; 644 | }; 645 | 9D7657251EEC4E8000016136 /* PBXTargetDependency */ = { 646 | isa = PBXTargetDependency; 647 | target = 9D7657191EEC4E8000016136 /* LLRegex tvOS */; 648 | targetProxy = 9D7657241EEC4E8000016136 /* PBXContainerItemProxy */; 649 | }; 650 | 9DD5D0611EEAB3EB009CAE13 /* PBXTargetDependency */ = { 651 | isa = PBXTargetDependency; 652 | target = 9DD5D0541EEAB3EB009CAE13 /* LLRegex iOS */; 653 | targetProxy = 9DD5D0601EEAB3EB009CAE13 /* PBXContainerItemProxy */; 654 | }; 655 | /* End PBXTargetDependency section */ 656 | 657 | /* Begin XCBuildConfiguration section */ 658 | 9D7656E41EEBF1D100016136 /* Debug */ = { 659 | isa = XCBuildConfiguration; 660 | buildSettings = { 661 | CLANG_ENABLE_MODULES = YES; 662 | CODE_SIGN_IDENTITY = "-"; 663 | COMBINE_HIDPI_IMAGES = YES; 664 | DEFINES_MODULE = YES; 665 | DEVELOPMENT_TEAM = ""; 666 | DYLIB_COMPATIBILITY_VERSION = 1; 667 | DYLIB_CURRENT_VERSION = 1; 668 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 669 | FRAMEWORK_VERSION = A; 670 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 671 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 672 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 673 | MACOSX_DEPLOYMENT_TARGET = 10.10; 674 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 675 | PRODUCT_NAME = LLRegex; 676 | PROVISIONING_PROFILE_SPECIFIER = ""; 677 | SDKROOT = macosx; 678 | SKIP_INSTALL = YES; 679 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 680 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 681 | SWIFT_VERSION = 4.0; 682 | }; 683 | name = Debug; 684 | }; 685 | 9D7656E51EEBF1D100016136 /* Release */ = { 686 | isa = XCBuildConfiguration; 687 | buildSettings = { 688 | CLANG_ENABLE_MODULES = YES; 689 | CODE_SIGN_IDENTITY = "-"; 690 | COMBINE_HIDPI_IMAGES = YES; 691 | DEFINES_MODULE = YES; 692 | DEVELOPMENT_TEAM = ""; 693 | DYLIB_COMPATIBILITY_VERSION = 1; 694 | DYLIB_CURRENT_VERSION = 1; 695 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 696 | FRAMEWORK_VERSION = A; 697 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 698 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 699 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 700 | MACOSX_DEPLOYMENT_TARGET = 10.10; 701 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 702 | PRODUCT_NAME = LLRegex; 703 | PROVISIONING_PROFILE_SPECIFIER = ""; 704 | SDKROOT = macosx; 705 | SKIP_INSTALL = YES; 706 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 707 | SWIFT_VERSION = 4.0; 708 | }; 709 | name = Release; 710 | }; 711 | 9D7656E61EEBF1D100016136 /* Debug */ = { 712 | isa = XCBuildConfiguration; 713 | buildSettings = { 714 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 715 | CLANG_ENABLE_MODULES = YES; 716 | CODE_SIGN_IDENTITY = "-"; 717 | COMBINE_HIDPI_IMAGES = YES; 718 | DEVELOPMENT_TEAM = 6F3LJ4NQ2D; 719 | INFOPLIST_FILE = LLRegexTests/Info.plist; 720 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 721 | MACOSX_DEPLOYMENT_TARGET = 10.10; 722 | PRODUCT_BUNDLE_IDENTIFIER = "com.lal.LLRegex-macOSTests"; 723 | PRODUCT_NAME = "$(TARGET_NAME)"; 724 | SDKROOT = macosx; 725 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 726 | SWIFT_VERSION = 4.0; 727 | }; 728 | name = Debug; 729 | }; 730 | 9D7656E71EEBF1D100016136 /* Release */ = { 731 | isa = XCBuildConfiguration; 732 | buildSettings = { 733 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 734 | CLANG_ENABLE_MODULES = YES; 735 | CODE_SIGN_IDENTITY = "-"; 736 | COMBINE_HIDPI_IMAGES = YES; 737 | DEVELOPMENT_TEAM = 6F3LJ4NQ2D; 738 | INFOPLIST_FILE = LLRegexTests/Info.plist; 739 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 740 | MACOSX_DEPLOYMENT_TARGET = 10.10; 741 | PRODUCT_BUNDLE_IDENTIFIER = "com.lal.LLRegex-macOSTests"; 742 | PRODUCT_NAME = "$(TARGET_NAME)"; 743 | SDKROOT = macosx; 744 | SWIFT_VERSION = 4.0; 745 | }; 746 | name = Release; 747 | }; 748 | 9D76572B1EEC4E8000016136 /* Debug */ = { 749 | isa = XCBuildConfiguration; 750 | buildSettings = { 751 | CLANG_ENABLE_MODULES = YES; 752 | CODE_SIGN_IDENTITY = ""; 753 | DEFINES_MODULE = YES; 754 | DEVELOPMENT_TEAM = ""; 755 | DYLIB_COMPATIBILITY_VERSION = 1; 756 | DYLIB_CURRENT_VERSION = 1; 757 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 758 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 759 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 760 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 761 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 762 | PRODUCT_NAME = LLRegex; 763 | PROVISIONING_PROFILE_SPECIFIER = ""; 764 | SDKROOT = appletvos; 765 | SKIP_INSTALL = YES; 766 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 767 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 768 | SWIFT_VERSION = 4.0; 769 | TARGETED_DEVICE_FAMILY = 3; 770 | TVOS_DEPLOYMENT_TARGET = 9.0; 771 | }; 772 | name = Debug; 773 | }; 774 | 9D76572C1EEC4E8000016136 /* Release */ = { 775 | isa = XCBuildConfiguration; 776 | buildSettings = { 777 | CLANG_ENABLE_MODULES = YES; 778 | CODE_SIGN_IDENTITY = ""; 779 | DEFINES_MODULE = YES; 780 | DEVELOPMENT_TEAM = ""; 781 | DYLIB_COMPATIBILITY_VERSION = 1; 782 | DYLIB_CURRENT_VERSION = 1; 783 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 784 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 785 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 786 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 787 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 788 | PRODUCT_NAME = LLRegex; 789 | PROVISIONING_PROFILE_SPECIFIER = ""; 790 | SDKROOT = appletvos; 791 | SKIP_INSTALL = YES; 792 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 793 | SWIFT_VERSION = 4.0; 794 | TARGETED_DEVICE_FAMILY = 3; 795 | TVOS_DEPLOYMENT_TARGET = 9.0; 796 | }; 797 | name = Release; 798 | }; 799 | 9D76572D1EEC4E8000016136 /* Debug */ = { 800 | isa = XCBuildConfiguration; 801 | buildSettings = { 802 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 803 | CLANG_ENABLE_MODULES = YES; 804 | DEVELOPMENT_TEAM = ""; 805 | INFOPLIST_FILE = LLRegexTests/Info.plist; 806 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 807 | PRODUCT_BUNDLE_IDENTIFIER = "com.lal.LLRegex-tvOSTests"; 808 | PRODUCT_NAME = "$(TARGET_NAME)"; 809 | PROVISIONING_PROFILE_SPECIFIER = ""; 810 | SDKROOT = appletvos; 811 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 812 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 813 | SWIFT_VERSION = 4.0; 814 | TVOS_DEPLOYMENT_TARGET = 10.2; 815 | }; 816 | name = Debug; 817 | }; 818 | 9D76572E1EEC4E8000016136 /* Release */ = { 819 | isa = XCBuildConfiguration; 820 | buildSettings = { 821 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 822 | CLANG_ENABLE_MODULES = YES; 823 | DEVELOPMENT_TEAM = ""; 824 | INFOPLIST_FILE = LLRegexTests/Info.plist; 825 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 826 | PRODUCT_BUNDLE_IDENTIFIER = "com.lal.LLRegex-tvOSTests"; 827 | PRODUCT_NAME = "$(TARGET_NAME)"; 828 | PROVISIONING_PROFILE_SPECIFIER = ""; 829 | SDKROOT = appletvos; 830 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 831 | SWIFT_VERSION = 4.0; 832 | TVOS_DEPLOYMENT_TARGET = 10.2; 833 | }; 834 | name = Release; 835 | }; 836 | 9D7657491EEC509A00016136 /* Debug */ = { 837 | isa = XCBuildConfiguration; 838 | buildSettings = { 839 | APPLICATION_EXTENSION_API_ONLY = YES; 840 | CLANG_ENABLE_MODULES = YES; 841 | CODE_SIGN_IDENTITY = ""; 842 | DEFINES_MODULE = YES; 843 | DEVELOPMENT_TEAM = ""; 844 | DYLIB_COMPATIBILITY_VERSION = 1; 845 | DYLIB_CURRENT_VERSION = 1; 846 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 847 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 848 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 849 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 850 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 851 | PRODUCT_NAME = LLRegex; 852 | PROVISIONING_PROFILE_SPECIFIER = ""; 853 | SDKROOT = watchos; 854 | SKIP_INSTALL = YES; 855 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 856 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 857 | SWIFT_VERSION = 4.0; 858 | TARGETED_DEVICE_FAMILY = 4; 859 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 860 | }; 861 | name = Debug; 862 | }; 863 | 9D76574A1EEC509A00016136 /* Release */ = { 864 | isa = XCBuildConfiguration; 865 | buildSettings = { 866 | APPLICATION_EXTENSION_API_ONLY = YES; 867 | CLANG_ENABLE_MODULES = YES; 868 | CODE_SIGN_IDENTITY = ""; 869 | DEFINES_MODULE = YES; 870 | DEVELOPMENT_TEAM = ""; 871 | DYLIB_COMPATIBILITY_VERSION = 1; 872 | DYLIB_CURRENT_VERSION = 1; 873 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 874 | INFOPLIST_FILE = "$(SRCROOT)/LLRegex/Info.plist"; 875 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 876 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 877 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 878 | PRODUCT_NAME = LLRegex; 879 | PROVISIONING_PROFILE_SPECIFIER = ""; 880 | SDKROOT = watchos; 881 | SKIP_INSTALL = YES; 882 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 883 | SWIFT_VERSION = 4.0; 884 | TARGETED_DEVICE_FAMILY = 4; 885 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 886 | }; 887 | name = Release; 888 | }; 889 | 9DD5D0671EEAB3EB009CAE13 /* Debug */ = { 890 | isa = XCBuildConfiguration; 891 | buildSettings = { 892 | ALWAYS_SEARCH_USER_PATHS = NO; 893 | CLANG_ANALYZER_NONNULL = YES; 894 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 895 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 896 | CLANG_CXX_LIBRARY = "libc++"; 897 | CLANG_ENABLE_MODULES = YES; 898 | CLANG_ENABLE_OBJC_ARC = YES; 899 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 900 | CLANG_WARN_BOOL_CONVERSION = YES; 901 | CLANG_WARN_COMMA = YES; 902 | CLANG_WARN_CONSTANT_CONVERSION = YES; 903 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 904 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 905 | CLANG_WARN_EMPTY_BODY = YES; 906 | CLANG_WARN_ENUM_CONVERSION = YES; 907 | CLANG_WARN_INFINITE_RECURSION = YES; 908 | CLANG_WARN_INT_CONVERSION = YES; 909 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 910 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 911 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 912 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 913 | CLANG_WARN_STRICT_PROTOTYPES = YES; 914 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 915 | CLANG_WARN_UNREACHABLE_CODE = YES; 916 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 917 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 918 | COPY_PHASE_STRIP = NO; 919 | CURRENT_PROJECT_VERSION = 1; 920 | DEBUG_INFORMATION_FORMAT = dwarf; 921 | ENABLE_STRICT_OBJC_MSGSEND = YES; 922 | ENABLE_TESTABILITY = YES; 923 | GCC_C_LANGUAGE_STANDARD = gnu99; 924 | GCC_DYNAMIC_NO_PIC = NO; 925 | GCC_NO_COMMON_BLOCKS = YES; 926 | GCC_OPTIMIZATION_LEVEL = 0; 927 | GCC_PREPROCESSOR_DEFINITIONS = ( 928 | "DEBUG=1", 929 | "$(inherited)", 930 | ); 931 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 932 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 933 | GCC_WARN_UNDECLARED_SELECTOR = YES; 934 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 935 | GCC_WARN_UNUSED_FUNCTION = YES; 936 | GCC_WARN_UNUSED_VARIABLE = YES; 937 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 938 | MACOSX_DEPLOYMENT_TARGET = 10.10; 939 | MTL_ENABLE_DEBUG_INFO = YES; 940 | ONLY_ACTIVE_ARCH = YES; 941 | SDKROOT = iphoneos; 942 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 943 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 944 | TARGETED_DEVICE_FAMILY = "1,2"; 945 | VERSIONING_SYSTEM = "apple-generic"; 946 | VERSION_INFO_PREFIX = ""; 947 | }; 948 | name = Debug; 949 | }; 950 | 9DD5D0681EEAB3EB009CAE13 /* Release */ = { 951 | isa = XCBuildConfiguration; 952 | buildSettings = { 953 | ALWAYS_SEARCH_USER_PATHS = NO; 954 | CLANG_ANALYZER_NONNULL = YES; 955 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 956 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 957 | CLANG_CXX_LIBRARY = "libc++"; 958 | CLANG_ENABLE_MODULES = YES; 959 | CLANG_ENABLE_OBJC_ARC = YES; 960 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 961 | CLANG_WARN_BOOL_CONVERSION = YES; 962 | CLANG_WARN_COMMA = YES; 963 | CLANG_WARN_CONSTANT_CONVERSION = YES; 964 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 965 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 966 | CLANG_WARN_EMPTY_BODY = YES; 967 | CLANG_WARN_ENUM_CONVERSION = YES; 968 | CLANG_WARN_INFINITE_RECURSION = YES; 969 | CLANG_WARN_INT_CONVERSION = YES; 970 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 971 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 972 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 973 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 974 | CLANG_WARN_STRICT_PROTOTYPES = YES; 975 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 976 | CLANG_WARN_UNREACHABLE_CODE = YES; 977 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 978 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 979 | COPY_PHASE_STRIP = NO; 980 | CURRENT_PROJECT_VERSION = 1; 981 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 982 | ENABLE_NS_ASSERTIONS = NO; 983 | ENABLE_STRICT_OBJC_MSGSEND = YES; 984 | GCC_C_LANGUAGE_STANDARD = gnu99; 985 | GCC_NO_COMMON_BLOCKS = YES; 986 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 987 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 988 | GCC_WARN_UNDECLARED_SELECTOR = YES; 989 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 990 | GCC_WARN_UNUSED_FUNCTION = YES; 991 | GCC_WARN_UNUSED_VARIABLE = YES; 992 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 993 | MACOSX_DEPLOYMENT_TARGET = 10.10; 994 | MTL_ENABLE_DEBUG_INFO = NO; 995 | SDKROOT = iphoneos; 996 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 997 | TARGETED_DEVICE_FAMILY = "1,2"; 998 | VALIDATE_PRODUCT = YES; 999 | VERSIONING_SYSTEM = "apple-generic"; 1000 | VERSION_INFO_PREFIX = ""; 1001 | }; 1002 | name = Release; 1003 | }; 1004 | 9DD5D06A1EEAB3EB009CAE13 /* Debug */ = { 1005 | isa = XCBuildConfiguration; 1006 | buildSettings = { 1007 | CLANG_ENABLE_MODULES = YES; 1008 | CODE_SIGN_IDENTITY = ""; 1009 | DEFINES_MODULE = YES; 1010 | DEVELOPMENT_TEAM = ""; 1011 | DYLIB_COMPATIBILITY_VERSION = 1; 1012 | DYLIB_CURRENT_VERSION = 1; 1013 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1014 | INFOPLIST_FILE = LLRegex/Info.plist; 1015 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1016 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1017 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1018 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 1019 | PRODUCT_NAME = LLRegex; 1020 | PROVISIONING_PROFILE_SPECIFIER = ""; 1021 | SKIP_INSTALL = YES; 1022 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1023 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1024 | SWIFT_VERSION = 4.0; 1025 | }; 1026 | name = Debug; 1027 | }; 1028 | 9DD5D06B1EEAB3EB009CAE13 /* Release */ = { 1029 | isa = XCBuildConfiguration; 1030 | buildSettings = { 1031 | CLANG_ENABLE_MODULES = YES; 1032 | CODE_SIGN_IDENTITY = ""; 1033 | DEFINES_MODULE = YES; 1034 | DEVELOPMENT_TEAM = ""; 1035 | DYLIB_COMPATIBILITY_VERSION = 1; 1036 | DYLIB_CURRENT_VERSION = 1; 1037 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 1038 | INFOPLIST_FILE = LLRegex/Info.plist; 1039 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 1040 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 1041 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1042 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegex; 1043 | PRODUCT_NAME = LLRegex; 1044 | PROVISIONING_PROFILE_SPECIFIER = ""; 1045 | SKIP_INSTALL = YES; 1046 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 1047 | SWIFT_VERSION = 4.0; 1048 | }; 1049 | name = Release; 1050 | }; 1051 | 9DD5D06D1EEAB3EB009CAE13 /* Debug */ = { 1052 | isa = XCBuildConfiguration; 1053 | buildSettings = { 1054 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1055 | CLANG_ENABLE_MODULES = YES; 1056 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 1057 | DEVELOPMENT_TEAM = ""; 1058 | INFOPLIST_FILE = LLRegexTests/Info.plist; 1059 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1060 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegexTests; 1061 | PRODUCT_NAME = "$(TARGET_NAME)"; 1062 | PROVISIONING_PROFILE_SPECIFIER = ""; 1063 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 1064 | SWIFT_VERSION = 4.0; 1065 | }; 1066 | name = Debug; 1067 | }; 1068 | 9DD5D06E1EEAB3EB009CAE13 /* Release */ = { 1069 | isa = XCBuildConfiguration; 1070 | buildSettings = { 1071 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1072 | CLANG_ENABLE_MODULES = YES; 1073 | DEVELOPMENT_TEAM = ""; 1074 | INFOPLIST_FILE = LLRegexTests/Info.plist; 1075 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1076 | PRODUCT_BUNDLE_IDENTIFIER = com.lal.LLRegexTests; 1077 | PRODUCT_NAME = "$(TARGET_NAME)"; 1078 | PROVISIONING_PROFILE_SPECIFIER = ""; 1079 | SWIFT_VERSION = 4.0; 1080 | }; 1081 | name = Release; 1082 | }; 1083 | /* End XCBuildConfiguration section */ 1084 | 1085 | /* Begin XCConfigurationList section */ 1086 | 9D7656E81EEBF1D100016136 /* Build configuration list for PBXNativeTarget "LLRegex macOS" */ = { 1087 | isa = XCConfigurationList; 1088 | buildConfigurations = ( 1089 | 9D7656E41EEBF1D100016136 /* Debug */, 1090 | 9D7656E51EEBF1D100016136 /* Release */, 1091 | ); 1092 | defaultConfigurationIsVisible = 0; 1093 | defaultConfigurationName = Release; 1094 | }; 1095 | 9D7656E91EEBF1D100016136 /* Build configuration list for PBXNativeTarget "LLRegex macOS Tests" */ = { 1096 | isa = XCConfigurationList; 1097 | buildConfigurations = ( 1098 | 9D7656E61EEBF1D100016136 /* Debug */, 1099 | 9D7656E71EEBF1D100016136 /* Release */, 1100 | ); 1101 | defaultConfigurationIsVisible = 0; 1102 | defaultConfigurationName = Release; 1103 | }; 1104 | 9D76572F1EEC4E8000016136 /* Build configuration list for PBXNativeTarget "LLRegex tvOS" */ = { 1105 | isa = XCConfigurationList; 1106 | buildConfigurations = ( 1107 | 9D76572B1EEC4E8000016136 /* Debug */, 1108 | 9D76572C1EEC4E8000016136 /* Release */, 1109 | ); 1110 | defaultConfigurationIsVisible = 0; 1111 | defaultConfigurationName = Release; 1112 | }; 1113 | 9D7657301EEC4E8000016136 /* Build configuration list for PBXNativeTarget "LLRegex tvOS Tests" */ = { 1114 | isa = XCConfigurationList; 1115 | buildConfigurations = ( 1116 | 9D76572D1EEC4E8000016136 /* Debug */, 1117 | 9D76572E1EEC4E8000016136 /* Release */, 1118 | ); 1119 | defaultConfigurationIsVisible = 0; 1120 | defaultConfigurationName = Release; 1121 | }; 1122 | 9D7657481EEC509A00016136 /* Build configuration list for PBXNativeTarget "LLRegex watchOS" */ = { 1123 | isa = XCConfigurationList; 1124 | buildConfigurations = ( 1125 | 9D7657491EEC509A00016136 /* Debug */, 1126 | 9D76574A1EEC509A00016136 /* Release */, 1127 | ); 1128 | defaultConfigurationIsVisible = 0; 1129 | defaultConfigurationName = Release; 1130 | }; 1131 | 9DD5D04F1EEAB3EB009CAE13 /* Build configuration list for PBXProject "LLRegex" */ = { 1132 | isa = XCConfigurationList; 1133 | buildConfigurations = ( 1134 | 9DD5D0671EEAB3EB009CAE13 /* Debug */, 1135 | 9DD5D0681EEAB3EB009CAE13 /* Release */, 1136 | ); 1137 | defaultConfigurationIsVisible = 0; 1138 | defaultConfigurationName = Release; 1139 | }; 1140 | 9DD5D0691EEAB3EB009CAE13 /* Build configuration list for PBXNativeTarget "LLRegex iOS" */ = { 1141 | isa = XCConfigurationList; 1142 | buildConfigurations = ( 1143 | 9DD5D06A1EEAB3EB009CAE13 /* Debug */, 1144 | 9DD5D06B1EEAB3EB009CAE13 /* Release */, 1145 | ); 1146 | defaultConfigurationIsVisible = 0; 1147 | defaultConfigurationName = Release; 1148 | }; 1149 | 9DD5D06C1EEAB3EB009CAE13 /* Build configuration list for PBXNativeTarget "LLRegex iOS Tests" */ = { 1150 | isa = XCConfigurationList; 1151 | buildConfigurations = ( 1152 | 9DD5D06D1EEAB3EB009CAE13 /* Debug */, 1153 | 9DD5D06E1EEAB3EB009CAE13 /* Release */, 1154 | ); 1155 | defaultConfigurationIsVisible = 0; 1156 | defaultConfigurationName = Release; 1157 | }; 1158 | /* End XCConfigurationList section */ 1159 | }; 1160 | rootObject = 9DD5D04C1EEAB3EB009CAE13 /* Project object */; 1161 | } 1162 | -------------------------------------------------------------------------------- /Project/LLRegex.xcodeproj/xcshareddata/xcschemes/LLRegex iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Project/LLRegex.xcodeproj/xcshareddata/xcschemes/LLRegex macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Project/LLRegex.xcodeproj/xcshareddata/xcschemes/LLRegex tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 67 | 73 | 74 | 75 | 76 | 77 | 78 | 84 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Project/LLRegex.xcodeproj/xcshareddata/xcschemes/LLRegex watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 72 | 73 | 74 | 75 | 77 | 78 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /Project/LLRegex/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.lal.LLRegex 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | LLRegex 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.2.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Project/LLRegex/LLRegex.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLRegex.h 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/9. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | //! Project version number for LLRegex. 12 | FOUNDATION_EXPORT double LLRegexVersionNumber; 13 | 14 | //! Project version string for LLRegex. 15 | FOUNDATION_EXPORT const unsigned char LLRegexVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Project/LLRegex/Playground.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Playground.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Yang on 2017/6/10. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | let numbers = Regex("(\\d)(\\d+)(\\d)") 12 | 13 | let insensitive = Regex("LLRegex", options: [.caseInsensitive]) 14 | 15 | let runtimeError = Regex("") // Runtime error would be raised 16 | 17 | let invalid = try? Regex(pattern: "") // nil returned 18 | 19 | let s = "123-45-6789-0-123-45-6789-01234" 20 | 21 | let subrange = s.characters.dropFirst(3).startIndex..\\d+)-(?\\d+)-(?\\d+)", options: .namedCaptureGroups) 63 | let s = "Today is 2017-06-23." 64 | 65 | for m in named.matches(in: s) { 66 | m.groups["year"]?.matched 67 | } 68 | 69 | named.replacingAllMatches(in: s, replacement: .replaceWithTemplate("${month}/${day}/${year}")) 70 | } 71 | 72 | public func replace() { 73 | 74 | numbers.replacingFirstMatch(in: s, replacement: .remove) 75 | 76 | numbers.replacingAllMatches(in: s, range: subrange, replacement: .replaceWithTemplate("$3$2$1")) 77 | 78 | numbers.replacingMatches(in: s) { (idx, match) -> Match.Replacing in 79 | 80 | switch idx { 81 | case 0: 82 | return .keep // Keep unchanged 83 | case 1: 84 | return .remove // Remove the matched string 85 | case 2: 86 | return .replaceWithTemplate("$1-$3") // Replace with template 87 | case 3: 88 | return .replaceWithString({ 89 | return String(match.matched.characters.reversed()) // Relace with string 90 | }()) 91 | default: 92 | return .stop // Stop replacing 93 | } 94 | } 95 | } 96 | 97 | public func string() { 98 | 99 | "123".isMatching("\\d+") 100 | "llregex".isMatching(insensitive) 101 | "123-456".isMatching("\\d+") 102 | 103 | "123".replacingAll("1", with: "!") 104 | "123".replacingAll(pattern: "(\\d)(\\d)", withTemplate: "$2$1") 105 | 106 | "123".replacingFirst(pattern: numbers, in: subrange, withTemplate: "!") 107 | 108 | s.split(seperator: "\\d") 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /Project/LLRegexTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLRegex 2 | 3 | [![Build Status](https://travis-ci.org/LittleRockInGitHub/LLRegex.svg?branch=master)](https://travis-ci.org/LittleRockInGitHub/LLRegex) 4 | [![CocoaPods Compatible](https://img.shields.io/cocoapods/v/LLRegex.svg)](https://img.shields.io/cocoapods/v/LLRegex.svg) 5 | [![Platform](https://img.shields.io/cocoapods/p/LLRegex.svg)](https://img.shields.io/cocoapods/p/LLRegex.svg) 6 | 7 | Regular expression library in Swift, wrapping NSRegularExpression. 8 | Don't hesitate to try out on [playground](https://github.com/LittleRockInGitHub/LLRegex/blob/master/LLRegex.playground.zip). 9 | 10 | ## Features 11 | * Value Semantics 12 | * Enumerates matches with Sequence 13 | * Named capture group (unavailable on iOS 8) 14 | * Range supported (NSRange eliminated) 15 | * Regex Options, Match Options 16 | * Find & Replace with flexibility 17 | * String matching, replacing, splitting 18 | 19 | ## Communication 20 | * If you **found a bug**, open an issue, typically with related pattern. 21 | * If you **have a feature request**, open an issue. 22 | 23 | ## Requirements 24 | 25 | - iOS 8.0+ / macOS 10.10+ / tvOS 9.0+ / watchOS 2.0+ 26 | - Xcode 8.1+ 27 | - Swift 3.2 28 | 29 | ## Installation 30 | 31 | ### CocoaPods 32 | 33 | ```ruby 34 | pod 'LLRegex', '~> 1.3' 35 | ``` 36 | 37 | ### Swift Package Manager 38 | 39 | ```swift 40 | dependencies: [ 41 | .Package(url: "https://github.com/LittleRockInGitHub/LLRegex.git", majorVersion: 1) 42 | ] 43 | ``` 44 | 45 | ## Usage 46 | 47 | ### Making a Regex 48 | 49 | ```swift 50 | let numbers = Regex("(\\d)(\\d+)(\\d)") 51 | 52 | let insensitive = Regex("LLRegex", options: [.caseInsensitive]) 53 | 54 | let runtimeError = Regex("") // Runtime error would be raised 55 | 56 | let invalid = try? Regex(pattern: "") // nil returned 57 | ``` 58 | 59 | ### Searching 60 | Method `matches(in:options:range:)` returns a sequence producing matches **lazily**, which is the only one for searching. All other variants were dropped thanks to the power of Sequence. 61 | 62 | ```swift 63 | let s = "123-45-6789-0-123-45-6789-01234" 64 | let subrange = s.characters.dropFirst(3).startIndex..\\d+)-(?\\d+)-(?\\d+)", options: .namedCaptureGroups) 105 | let s = "Today is 2017-06-23." 106 | 107 | for m in named.matches(in: s) { 108 | m.groups["year"]?.matched 109 | } 110 | 111 | named.replacingAllMatches(in: s, replacement: .replaceWithTemplate("${month}/${day}/${year}")) // Today is 06/23/2017. 112 | ``` 113 | - Note: If the comment in pattern contains the notation of capture group, the detection for named capture group will fail. 114 | 115 | ### Replacing 116 | 117 | ```swift 118 | numbers.replacingFirstMatch(in: s, replacement: .remove) 119 | 120 | numbers.replacingAllMatches(in: s, range: subrange, replacement: .replaceWithTemplate("$3$2$1")) 121 | ``` 122 | 123 | Flexible Find & Replace is offered by `replacingMatches(in:options:range:replacing:)`. 124 | 125 | ```swift 126 | numbers.replacingMatches(in: s) { (idx, match) -> Match.Replacing in 127 | 128 | switch idx { 129 | case 0: 130 | return .keep // Keeps unchanged 131 | case 1: 132 | return .remove // Removes the matched string 133 | case 2: 134 | return .replaceWithTemplate("($1-$3)") // Replaces with template 135 | case 3: 136 | return .replaceWithString(String(match.matched.characters.reversed())) // Replaces with string 137 | default: 138 | return .stop // Stops replacing 139 | } 140 | } 141 | ``` 142 | 143 | ### String Matching 144 | 145 | ```swift 146 | "123".isMatching("\\d+") 147 | "llregex".isMatching(insensitive) // Regex is accepted 148 | "123-456".isMatching("\\d+") // isMatching(_:) checks whether matches entirely 149 | ``` 150 | 151 | ### String Replacing 152 | - Note: Two variants - one with pattern and template label, the other is not. 153 | 154 | ```swift 155 | "123".replacingAll("1", with: "$0") 156 | "123-321".replacingAll(pattern: "(\\d)(\\d)", withTemplate: "$2$1") 157 | 158 | s.replacingFirst(pattern: numbers, in: subrange, withTemplate: "!") 159 | ``` 160 | 161 | ### String Splitting 162 | 163 | ```swift 164 | s.split(seperator: "\\d") 165 | s.split(seperator: numbers, maxSplits: 2, omittingEmptyString: false) 166 | ``` 167 | 168 | -------------------------------------------------------------------------------- /Sources/Match.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Match.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/5/31. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | // MARK: MatchProtocol 13 | 14 | //// A type that repsents a match. 15 | public protocol MatchProtocol { 16 | 17 | /// The searched string. 18 | var searched: String { get } 19 | 20 | /// The matched string. 21 | var matched: String { get } 22 | 23 | /// The matched range. 24 | var range: Range? { get } 25 | } 26 | 27 | extension MatchProtocol { 28 | 29 | public var matched: String { 30 | return range.map { String(searched[$0]) } ?? "" 31 | } 32 | } 33 | 34 | 35 | protocol _NSRangeBasedMatch : MatchProtocol { 36 | 37 | var nsRange: NSRange { get } 38 | } 39 | 40 | extension _NSRangeBasedMatch { 41 | 42 | public var range: Range? { 43 | return nsRange.toRange(in: searched) 44 | } 45 | 46 | public var matched: String { 47 | guard nsRange.location != NSNotFound else { return ""} 48 | return (searched as NSString).substring(with: nsRange) as String 49 | } 50 | } 51 | 52 | 53 | // MARK: Match 54 | 55 | /// A type that represents a match searched by regular expression. 56 | public class Match : _NSRangeBasedMatch { 57 | 58 | /// Options for matching 59 | public struct Options : OptionSetAdapting { 60 | 61 | typealias Adopated = NSRegularExpression.MatchingOptions 62 | 63 | public let rawValue: UInt 64 | 65 | public init(rawValue: UInt) { 66 | self.rawValue = rawValue 67 | } 68 | 69 | /// Same as NSRegularExpression.MatchingOptions.anchored 70 | public static let anchored = Options(adapted: .anchored) 71 | /// Same as NSRegularExpression.MatchingOptions.withTransparentBounds 72 | public static let withTransparentBounds = Options(adapted: .withTransparentBounds) 73 | /// Same as NSRegularExpression.MatchingOptions.withoutAnchoringBounds 74 | public static let withoutAnchoringBounds = Options(adapted: .withoutAnchoringBounds) 75 | 76 | static let adaptedOptions: NSRegularExpression.MatchingOptions = [.anchored, 77 | .withTransparentBounds, 78 | .withoutAnchoringBounds] 79 | } 80 | 81 | /// The searched string. 82 | public let searched: String 83 | 84 | /// The wrapped NSTextCheckingResult. 85 | public let result: NSTextCheckingResult 86 | 87 | var nsRange: NSRange { 88 | return result.range 89 | } 90 | 91 | init?(searched: String, result: NSTextCheckingResult, regex: Regex) { 92 | self.searched = searched 93 | self.result = result 94 | self.regex = regex 95 | 96 | self.groups = CaptureGroups(match: self) 97 | } 98 | 99 | /// The searching regex. 100 | public let regex: Regex! 101 | 102 | /// The captures groups. 103 | private(set) public var groups: CaptureGroups! 104 | } 105 | 106 | extension Match { 107 | 108 | 109 | /// A type thats represents capture group in a match. 110 | public struct CaptureGroup : _NSRangeBasedMatch { 111 | 112 | // The index in the match. 113 | public let index: Int 114 | 115 | private let match: Match 116 | 117 | // The searched string. 118 | public var searched: String { return match.searched } 119 | 120 | var nsRange: NSRange { 121 | #if swift(>=4) 122 | return match.result.range(at: index) 123 | #else 124 | return match.result.rangeAt(index) 125 | #endif 126 | } 127 | 128 | fileprivate init(index: Int, match: Match) { 129 | self.match = match 130 | self.index = index 131 | } 132 | } 133 | 134 | /// A collection that represents caputure groups. 135 | public class CaptureGroups : RandomAccessCollection { 136 | 137 | private let match: Match 138 | 139 | public typealias Element = CaptureGroup 140 | 141 | public typealias Index = Int 142 | 143 | public subscript(index: Int) -> CaptureGroup { 144 | return CaptureGroup(index: index, match: match) 145 | } 146 | 147 | public subscript(name: String) -> CaptureGroup? { 148 | return match.regex.namedCaptureGroupsInfo?[name].map { self[$0] } 149 | } 150 | 151 | fileprivate init(match: Match) { 152 | self.match = match 153 | } 154 | 155 | public var startIndex: Int { return 0 } 156 | 157 | public var endIndex: Int { return match.result.numberOfRanges } 158 | } 159 | } 160 | 161 | // MARK: Replacement 162 | 163 | extension Match { 164 | 165 | /** 166 | Returns a replacement string by performing template substitution. 167 | - parameter template: The template for substitution. 168 | - returns: The replacement string. 169 | */ 170 | public func replacement(withTemplate template: String) -> String { 171 | 172 | var template = template 173 | 174 | if regex.options.contains(.namedCaptureGroups) { 175 | 176 | let info = regex.namedCaptureGroupsInfo ?? [:] 177 | 178 | struct RE { 179 | static let named: Regex = Regex("(\\\\*)\\$\\{(\\w+)\\}") 180 | } 181 | 182 | template = RE.named.replacingMatches(in: template) { (_, match) -> Match.Replacing in 183 | 184 | guard match.groups[1].matched.utf16.count % 2 == 0 else { return .keep } 185 | 186 | if let idx = info[match.groups[2].matched] { 187 | return .replaceWithTemplate("$1\\$\(idx)") 188 | } else { 189 | return .remove 190 | } 191 | } 192 | } 193 | 194 | return result.regularExpression!.replacementString(for: result, in: searched, offset: 0, template: template) 195 | } 196 | } 197 | 198 | // MARK: Template Escape 199 | 200 | extension Match { 201 | 202 | /// Returns a template string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters 203 | public static func escapedTemplate(for string: String) -> String { 204 | return NSRegularExpression.escapedTemplate(for: string) 205 | } 206 | } 207 | 208 | extension String { 209 | 210 | /// Returns a template string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters 211 | public func escapedAsTemplate() -> String { 212 | return Match.escapedTemplate(for: self) 213 | } 214 | } 215 | 216 | -------------------------------------------------------------------------------- /Sources/NSRange+Util.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSRange+Util.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/2. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension NSRange { 12 | 13 | init(start: Int, end: Int) { 14 | self.init(location: start, length: end - start) 15 | } 16 | 17 | var isEmpty: Bool { 18 | return length == 0 19 | } 20 | 21 | func contains(_ loc: Int) -> Bool { 22 | return NSLocationInRange(loc, self) 23 | } 24 | 25 | var start: Int { 26 | get { 27 | return location 28 | } 29 | set { 30 | self = NSRange(start: newValue, end: end) 31 | } 32 | } 33 | 34 | var end: Int { 35 | get { 36 | return NSMaxRange(self) 37 | } 38 | set { 39 | self = NSRange(start: start, end: newValue) 40 | } 41 | } 42 | 43 | 44 | } 45 | 46 | #if !swift(>=3.2) 47 | extension NSRange : Equatable { 48 | public static func ==(lhs: NSRange, rhs: NSRange) -> Bool { 49 | return NSEqualRanges(lhs, rhs) 50 | } 51 | } 52 | #endif 53 | 54 | -------------------------------------------------------------------------------- /Sources/OptionSetAdapting.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OptionSetAdapting.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Yang on 2017/6/22. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | protocol OptionSetAdapting : OptionSet { 13 | 14 | associatedtype Adapted: OptionSet 15 | 16 | init(adapted options: Adapted) 17 | 18 | func toAdapted() -> Adapted 19 | 20 | static var adaptedOptions: Adapted { get } 21 | } 22 | 23 | extension OptionSetAdapting where RawValue == Adapted.RawValue { 24 | 25 | static var adaptingOptions: Self { return Self.init(adapted: Self.adaptedOptions) } 26 | 27 | init(adapted options: Adapted) { 28 | self.init(rawValue: options.intersection(Self.adaptedOptions).rawValue) 29 | } 30 | 31 | func toAdapted() -> Adapted { 32 | return Adapted.init(rawValue: self.rawValue).intersection(Self.adaptedOptions) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Sources/Regex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Regex.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/5/31. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /// A type that is used to reprensent and apply regular expreesion to Unicode strings, which wrapps NSRegularExpression. 13 | public struct Regex { 14 | 15 | /// Options of Regex. 16 | public struct Options : OptionSetAdapting { 17 | 18 | typealias Adapted = NSRegularExpression.Options 19 | 20 | private static let reserved: UInt = 16 21 | 22 | public let rawValue: UInt 23 | 24 | public init(rawValue: UInt) { 25 | self.rawValue = rawValue 26 | } 27 | 28 | /// Same as NSRegularExpression.Option.caseInsensitive 29 | public static let caseInsensitive = Options(adapted: .caseInsensitive) 30 | /// Same as NSRegularExpression.Option.allowCommentsAndWhitespace 31 | public static let allowCommentsAndWhitespace = Options(adapted: .allowCommentsAndWhitespace) 32 | /// Same as NSRegularExpression.Option.ignoreMetacharacters 33 | public static let ignoreMetacharacters = Options(adapted: .ignoreMetacharacters) 34 | /// Same as NSRegularExpression.Option.dotMatchesLineSeparators 35 | public static let dotMatchesLineSeparators = Options(adapted: .dotMatchesLineSeparators) 36 | /// Same as NSRegularExpression.Option.anchorsMatchLines 37 | public static let anchorsMatchLines = Options(adapted: .anchorsMatchLines) 38 | /// Same as NSRegularExpression.Option.useUnixLineSeparators 39 | public static let useUnixLineSeparators = Options(adapted: .useUnixLineSeparators) 40 | /// Same as NSRegularExpression.Option.useUnicodeWordBoundaries 41 | public static let useUnicodeWordBoundaries = Options(adapted: .useUnicodeWordBoundaries) 42 | /// Enables named capture groups feature 43 | public static let namedCaptureGroups = Options(rawValue: 1 << reserved) 44 | 45 | static let adaptedOptions: NSRegularExpression.Options = [.caseInsensitive, 46 | .allowCommentsAndWhitespace, 47 | .ignoreMetacharacters, 48 | .dotMatchesLineSeparators, 49 | .anchorsMatchLines, 50 | .useUnixLineSeparators, 51 | .useUnicodeWordBoundaries] 52 | 53 | } 54 | 55 | private let _regularExpression: NSRegularExpression 56 | 57 | /// Wrapped NSRegularExpression. 58 | public var regularExpression: NSRegularExpression { 59 | get { 60 | return _regularExpression 61 | } 62 | set { 63 | self = Regex(regularExpression: newValue) 64 | } 65 | } 66 | 67 | /** 68 | Creates a `Regex` with unchecked string literal and options. Runtime error is raised if the unchecked pattern is invalid. 69 | - parameter uncheckedPattern: The unchecked regulare expression pattern. 70 | - parameter options: The regular expression options that are applied to the expression during matching. Empty options by default. 71 | - returns: An instance with given pattern and options. Runtime error is raised if the unchecked pattern is invalid. 72 | */ 73 | public init(_ uncheckedPattern: StaticString, options: Options = []) { 74 | do { 75 | try self.init(pattern: uncheckedPattern.description, options: options) 76 | } catch { 77 | fatalError("Pattern \(uncheckedPattern) is invalid.") 78 | } 79 | } 80 | 81 | /** 82 | Creates a `Regex` with pattern and options. 83 | - parameter pattern: The regulare expression pattern. 84 | - parameter options: The regular expression options that are applied to the expression during matching. Empty options by default. 85 | - returns: An instance with given pattern and options. 86 | - throws: An error if failed. 87 | */ 88 | public init(pattern: String, options: Options = []) throws { 89 | let re = try NSRegularExpression(pattern: pattern, options: options.toAdapted()) 90 | self._regularExpression = re 91 | self._options = options 92 | 93 | if #available(iOS 9, *), options.contains(.namedCaptureGroups) { 94 | self.namedCaptureGroupsInfo = extractNamedCaptureGroups(in: pattern, expectedGroupsCount: re.numberOfCaptureGroups) 95 | } else { 96 | self.namedCaptureGroupsInfo = [:] 97 | } 98 | } 99 | 100 | /** 101 | Creates a `Regex` with an instance of NSRegularExpression. 102 | - parameters regularExpression: A compiled NSRegulareExpression. 103 | - returns: An instance wrapping given NSRegularExpression. 104 | */ 105 | 106 | public init(regularExpression: NSRegularExpression) { 107 | self._regularExpression = regularExpression 108 | self._options = Options(adapted: regularExpression.options) 109 | self.namedCaptureGroupsInfo = [:] 110 | } 111 | 112 | 113 | /// The pattern value. 114 | public var pattern: String { return regularExpression.pattern } 115 | 116 | /** 117 | Set a new pattern value. 118 | - parameter pattern: A new pattern. 119 | - throws: An error if pattern is invalid. 120 | */ 121 | public mutating func setPattern(_ pattern: String) throws { 122 | self = try Regex(pattern: pattern, options: self.options) 123 | } 124 | 125 | private let _options: Options 126 | 127 | /// The options value. 128 | public var options: Options { 129 | get { 130 | return _options 131 | } 132 | set { 133 | self = try! Regex(pattern: pattern, options: newValue) 134 | } 135 | } 136 | 137 | 138 | /// The number of capture groups. 139 | public var numberOfCaptureGroups: Int { return regularExpression.numberOfCaptureGroups } 140 | 141 | let namedCaptureGroupsInfo: [String: Int]? 142 | 143 | } 144 | 145 | // MARK: Equatable 146 | 147 | extension Regex : Equatable { 148 | 149 | public static func ==(lhs: Regex, rhs: Regex) -> Bool { 150 | return lhs.pattern == rhs.pattern && lhs.options == rhs.options 151 | } 152 | } 153 | 154 | // MARK: Hashable 155 | 156 | extension Regex : Hashable { 157 | 158 | public var hashValue: Int { 159 | return pattern.hashValue + options.rawValue.hashValue * 100 160 | } 161 | } 162 | 163 | // MARK: Match 164 | 165 | extension Regex { 166 | 167 | /** 168 | Returns a sequence producing matches **lazily** in the searched string. 169 | - parameter string: The searched string. 170 | - parameter options: The Match options. 171 | - parameter range: The searched range. `nil` indicates searching in the whole range of given string. `nil` by default. 172 | */ 173 | public func matches(in string: String, options: Match.Options = [], range: Range? = nil) -> Match.Sequence { 174 | 175 | return Match.Sequence(iterator: Match.Iterator(regex: self, searched: string, options: options, range: range)) 176 | } 177 | } 178 | 179 | extension Match { 180 | 181 | /// A Iterator type iterates the matches. 182 | public struct Iterator: IteratorProtocol { 183 | 184 | let searched: String 185 | let regex: Regex! 186 | let options: NSRegularExpression.MatchingOptions 187 | let range: NSRange? 188 | 189 | private var lastMatched: NSRange? 190 | private var current: NSRange? 191 | 192 | init() { 193 | self.searched = "" 194 | self.options = [] 195 | self.range = nil 196 | self.regex = nil 197 | } 198 | 199 | init(regex: Regex, searched: String, options: Options, nsRange: NSRange) { 200 | self.regex = regex 201 | self.searched = searched 202 | 203 | self.options = options.toAdapted().union(.reportCompletion) 204 | 205 | self.range = nsRange 206 | self.current = nsRange 207 | } 208 | 209 | init(regex: Regex, searched: String, options: Options, range: Range? = nil) { 210 | 211 | self.init(regex: regex, searched: searched, options: options, nsRange: (range ?? searched.startIndex.. Match? { 215 | 216 | guard let current = current else { return nil } 217 | 218 | var match: Match? 219 | 220 | regex.regularExpression.enumerateMatches(in: searched, options: options, range: current) { (r, flags, stop) in 221 | 222 | guard let r = r else { 223 | stop.pointee = true 224 | match = nil 225 | return 226 | } 227 | 228 | if lastMatched != r.range, let m = Match(searched: searched, result: r, regex: regex) { 229 | stop.pointee = true 230 | match = m 231 | } 232 | } 233 | 234 | lastMatched = match?.result.range 235 | 236 | if let match = match { 237 | self.current?.start = match.result.range.end 238 | return match 239 | } else { 240 | self.current = nil 241 | return nil 242 | } 243 | } 244 | 245 | 246 | } 247 | 248 | /// A Sequence type produces matches. 249 | public struct Sequence: Swift.Sequence { 250 | 251 | let iterator: Iterator 252 | 253 | public func makeIterator() -> Iterator { 254 | return iterator 255 | } 256 | } 257 | } 258 | 259 | extension Match.Sequence { 260 | 261 | /// Returns the first match. `nil` if no matches. 262 | public var first: Match? { 263 | return self.first { _ in true } 264 | } 265 | 266 | /// Returns all matches. 267 | public var all: [Match] { 268 | return self.iterator.makeAllMatches() 269 | } 270 | } 271 | 272 | extension Match.Iterator { 273 | 274 | func makeAllMatches() -> [Match] { 275 | 276 | guard let range = self.range else { return [] } 277 | 278 | return self.regex.regularExpression.matches(in: searched, options: options, range: range).flatMap({ Match(searched: searched, result: $0, regex: regex) 279 | }) 280 | } 281 | } 282 | 283 | // MARK: Replace 284 | 285 | extension Match { 286 | 287 | /** 288 | `Replacing` defines the actions in match replacing. 289 | * stop: Stops the replacing process. 290 | * replaceWithString(_): Replaces the range of match with given string. 291 | * replaceWithString(_): Replace the range of match with given template for match. 292 | * remove: Removes string in the range of match. 293 | * keep: Keep unchanged. 294 | */ 295 | public enum Replacing { 296 | /// Stops the replacing process. 297 | case stop 298 | /// Replaces the range of match with given string. 299 | case replaceWithString(String) 300 | /// Replace the range of match with given template for match. 301 | case replaceWithTemplate(String) 302 | /// Removes string in the range of match. 303 | case remove 304 | /// Keep unchanged. 305 | case keep 306 | } 307 | } 308 | 309 | extension Regex { 310 | 311 | /** 312 | Returns a string by replacing the first match in the searched string. 313 | - parameter string: The searched string. 314 | - parameter options: The Match options. Empty options by default. 315 | - parameter range: The searched range. 'nil' indicates searching of the whole string. 'nil' by default. 316 | - parameter replacement: The replacement action. 317 | - returns: A string by replacing the first match in the searched string. 318 | */ 319 | public func replacingFirstMatch(in string: String, options: Match.Options = [], range: Range? = nil, replacement: Match.Replacing) -> String { 320 | 321 | switch replacement { 322 | case .stop, .keep: 323 | return string 324 | default: 325 | return replacingMatches(in: string, options: options, range: range) { idx, match in 326 | return idx == 0 ? replacement : .stop 327 | } 328 | } 329 | } 330 | 331 | /** 332 | Returns a string by replacing matches in the searched string. 333 | - parameter string: The searched string. 334 | - parameter options: The Match options. Empty options by default. 335 | - parameter range: The searched range. 'nil' indicates searching of the whole string. 'nil' by default. 336 | - parameter replacement: The replacement action. 337 | - returns: A string by replacing matches in the searched string 338 | */ 339 | public func replacingAllMatches(in string: String, options: Match.Options = [], range: Range? = nil, replacement: Match.Replacing) -> String { 340 | 341 | switch replacement { 342 | case .stop, .keep: 343 | return string 344 | default: 345 | return replacingMatches(in: string, options: options, range: range) { _, _ in return replacement } 346 | } 347 | } 348 | 349 | /** 350 | Returns a string by replacing all matches in the searched string. 351 | - parameter string: The searched string. 352 | - parameter options: The Match options. Empty options by default. 353 | - parameter range: The searched range. 'nil' indicates searching of the whole string. 'nil' by default. 354 | - parameter replacing: The replacing handler. 355 | - returns: A string by replacing all matches in the searched string. 356 | */ 357 | public func replacingMatches(in string: String, options: Match.Options = [], range: Range? = nil, replacing: (_ idx: Int, _ match: Match) throws -> Match.Replacing) rethrows -> String { 358 | 359 | var replacements: [(Range, String)] = [] 360 | 361 | Iterating: for (idx, match) in IteratorSequence(Match.Iterator(regex: self, searched: string, options: options, range: range)).enumerated() { 362 | 363 | let replacement: String 364 | 365 | switch try replacing(idx, match) { 366 | case .stop: 367 | break Iterating 368 | case .keep: 369 | continue 370 | case .remove: 371 | replacement = "" 372 | case .replaceWithString(let s): 373 | replacement = s 374 | case .replaceWithTemplate(let template): 375 | replacement = match.replacement(withTemplate: template) 376 | } 377 | 378 | if let range = match.range { 379 | replacements.append((range, replacement)) 380 | } 381 | } 382 | 383 | var reval = string 384 | replacements.reversed().forEach { reval.replaceSubrange($0.0, with: $0.1) } 385 | 386 | return reval 387 | } 388 | 389 | } 390 | 391 | // MARK: Pattern Escape 392 | 393 | extension Regex { 394 | 395 | //// Returns a string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters. 396 | public static func escapedPattern(for string: String) -> String { 397 | return NSRegularExpression.escapedPattern(for: string) 398 | } 399 | } 400 | 401 | extension String { 402 | 403 | /// Returns a string by adding backslash escapes as necessary to protect any characters that would match as pattern metacharacters. 404 | public func escapedAsPattern() -> String { 405 | return Regex.escapedPattern(for: self) 406 | } 407 | } 408 | 409 | // MARK: RegexConvertible 410 | 411 | 412 | /// A type that is possible to be converted to `Regex'. 413 | public protocol RegexConvertible { 414 | 415 | /// Returns a converted `Regex`. 416 | var asRegex: Regex? { get } 417 | 418 | /// The pattern value. 419 | var pattern: String { get } 420 | 421 | /// The options value. 422 | var options: Regex.Options { get } 423 | } 424 | 425 | extension RegexConvertible { 426 | 427 | public var asRegex: Regex? { 428 | return try? Regex(pattern: self.pattern, options: self.options) 429 | } 430 | 431 | public var options: Regex.Options { return [] } 432 | } 433 | 434 | extension Regex : RegexConvertible { 435 | 436 | public var asRegex: Regex? { return self } 437 | } 438 | 439 | extension String : RegexConvertible { 440 | 441 | public var pattern: String { return "(?:\(self))" } 442 | } 443 | 444 | // MARK: NamedCaptureGroup 445 | 446 | func extractNamedCaptureGroups(in pattern: String, expectedGroupsCount: Int) -> [String: Int]? { 447 | struct RE { 448 | static let captureGroup: Regex = Regex("(\\\\*+)\\((?!\\?)") 449 | static let namedCaptureGroup: Regex = Regex("(\\\\*+)\\(\\?<(\\w+)>") 450 | } 451 | 452 | let captureGroups = RE.captureGroup.matches(in: pattern).filter { $0.groups[1].matched.utf16.count % 2 == 0 } 453 | let namedCaptureGroups = RE.namedCaptureGroup.matches(in: pattern).filter { $0.groups[1].matched.utf16.count % 2 == 0 } 454 | 455 | guard captureGroups.count + namedCaptureGroups.count == expectedGroupsCount else { return nil } 456 | 457 | let allGroups = (captureGroups + namedCaptureGroups).sorted { $0.range!.lowerBound < $1.range!.lowerBound } 458 | 459 | var reval = [String: Int]() 460 | 461 | for (idx, match) in allGroups.enumerated() { 462 | guard match.regex == RE.namedCaptureGroup else { continue } 463 | reval[match.groups[2].matched] = idx + 1 464 | } 465 | 466 | return reval 467 | } 468 | 469 | -------------------------------------------------------------------------------- /Sources/String+Regex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String+Regex.swift 3 | // LRegex 4 | // 5 | // Created by Rock Young on 2017/5/31. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | extension String { 13 | 14 | // MARK: Matching 15 | 16 | /** 17 | Returns whether `self` is matching given pattern. 18 | - parameter pattern: An element which is possible to be converted to `Regex`. 19 | - parameter entirely: Indicats whether should matches the string entirely. `true` by default. 20 | - returns: Whether 'self' is matching given pattern. `false` if regex conversion failed. 21 | */ 22 | public func isMatching(_ pattern: RegexConvertible, entirely: Bool = true) -> Bool { 23 | 24 | guard let regex = (entirely ? try? Regex(pattern: "\\A(:?\(pattern.pattern))\\Z", options: pattern.options) : pattern.asRegex) else { return false } 25 | 26 | return regex.matches(in: self).first != nil 27 | } 28 | 29 | // MARK: Replace All 30 | 31 | /** 32 | Returns a string made by replacing all matches in `self` searched by given pattern with given template. 33 | - parameter pattern: An element which is possible to be converted to `Regex`. 34 | - parameter range: The searched range. 'nil' indicates the whole range. 35 | - parameter template: The template string. 36 | - returns: A string made by replacing all matches in `self`. The original string is returned if regex conversion failed. 37 | */ 38 | public func replacingAll(pattern: RegexConvertible, in range : Range? = nil, withTemplate template: String) -> String { 39 | return pattern.asRegex?.replacingAllMatches(in: self, range: range,replacement: .replaceWithTemplate(template)) ?? self 40 | } 41 | 42 | /** 43 | Returns a string made by replacing all given string with another string. 44 | - parameter string: A string to search. 45 | - parameter range: The searched range. 'nil' indicates the whole range. 46 | - parameter replacement: The replacement string. 47 | - returns: A string made by replacing all given string with another string. 48 | */ 49 | public func replacingAll(_ string: String, in range : Range? = nil, with replacement: String) -> String { 50 | return string.escapedAsPattern().asRegex!.replacingAllMatches(in: self, replacement: .replaceWithString(replacement)) 51 | } 52 | 53 | /** 54 | Replaces all matches in `self` searched by given pattern with given template. Nothing happened if regex conversion failed. 55 | - parameter pattern: An element which is possible to be converted to `Regex`. 56 | - parameter range: The searched range. 'nil' indicates the whole range. 57 | - parameter template: The template string. 58 | */ 59 | public mutating func replaceAll(pattern: RegexConvertible, in range : Range? = nil, withTemplate template: String) { 60 | 61 | self = replacingAll(pattern: pattern, in: range, withTemplate: template) 62 | } 63 | 64 | /** 65 | Replaces all given string with another string. 66 | - parameter string: A string to search. 67 | - parameter range: The searched range. 'nil' indicates the whole range. 68 | - parameter replacement: The replacement string. 69 | */ 70 | public mutating func replaceAll(_ string: String, in range : Range? = nil, with replacement: String) { 71 | self = replacingAll(string, in: range, with: replacement) 72 | } 73 | 74 | // MARK: Replace First 75 | 76 | /** 77 | Returns a string made by replacing the first match in `self` searched by given pattern with given template. 78 | - parameter pattern: An element which is possible to be converted to `Regex`. 79 | - parameter range: The searched range. 'nil' indicates the whole range. 80 | - parameter template: The template string. 81 | - returns: A string made by replacing the first match in `self`. The original string is returned if regex conversion failed. 82 | */ 83 | public func replacingFirst(pattern: RegexConvertible, in range : Range? = nil, withTemplate template: String) -> String { 84 | 85 | return pattern.asRegex?.replacingFirstMatch(in: self, range: range, replacement: .replaceWithTemplate(template)) ?? self 86 | } 87 | 88 | /** 89 | Returns a string made by replacing the first given string with another string. 90 | - parameter string: A string to search. 91 | - parameter range: The searched range. 'nil' indicates the whole range. 92 | - parameter replacement: The replacement string. 93 | - returns: A string made by replacing the first given string with another string. 94 | */ 95 | public func replacingFirst(_ string: String, in range : Range? = nil, with replacement: String) -> String { 96 | 97 | return string.escapedAsPattern().asRegex!.replacingFirstMatch(in: self, range: range, replacement: .replaceWithString(replacement)) 98 | } 99 | 100 | /** 101 | Replaces the first match in `self` searched by given pattern with given template. Nothing happened if regex conversion failed. 102 | - parameter pattern: An element which is possible to be converted to `Regex`. 103 | - parameter range: The searched range. 'nil' indicates the whole range. 104 | - parameter template: The template string. 105 | */ 106 | public mutating func replaceFirst(pattern: RegexConvertible, in range : Range? = nil, withTemplate template: String) { 107 | self = replacingFirst(pattern: pattern, in: range, withTemplate: template) 108 | } 109 | 110 | /** 111 | Replaces the first given string with another string. 112 | - parameter string: A string to search. 113 | - parameter range: The searched range. 'nil' indicates the whole range. 114 | - parameter replacement: The replacement string. 115 | */ 116 | public mutating func replaceFirst(_ string: String, in range : Range? = nil, with replacement: String) { 117 | self = replacingFirst(string, in: range, with: replacement) 118 | } 119 | 120 | // MARK: Split 121 | 122 | /** 123 | Returns string array, in order, around elements equal to the given element. 124 | - parameter seperator: The pattern thats should be split upon. 125 | - parameter maxSplits: The maximum number of times to split 'self', or one less than the number of strings to return. `maxSplits` must be greater than or equal to zero. `Int.max` by default. 126 | - parameter omittingEmptyString: If true, only nonempty strings are returned. 'true' by default. 127 | - returns: The strings, splits from 'self'. 128 | */ 129 | public func split(seperator: RegexConvertible, maxSplits: Int = Int.max, omittingEmptyString: Bool = true) -> [Substring] { 130 | 131 | precondition(maxSplits >= 0) 132 | 133 | var reval: [Substring] = [] 134 | 135 | let appendRange: (Range) -> Void 136 | 137 | if omittingEmptyString { 138 | appendRange = { 139 | if !$0.isEmpty { 140 | reval.append(self[$0]) 141 | } 142 | } 143 | } else { 144 | appendRange = { 145 | reval.append(self[$0]) 146 | } 147 | } 148 | 149 | var current: String.Index = startIndex 150 | 151 | if let regex = seperator.asRegex { 152 | 153 | for (idx, match) in regex.matches(in: self).enumerated() { 154 | 155 | guard idx < maxSplits, let range = match.range else { break } 156 | 157 | appendRange(current.. NSRange { 15 | return NSRange(string.utf16Offset(fromIndex: lowerBound).. Range? { 23 | 24 | guard let range = Range(self), let start = string.index(fromUTF16Offset: range.lowerBound), let end = string.index(fromUTF16Offset: range.upperBound) else { return nil } 25 | 26 | return start.. String.Index? { 37 | #if swift(>=3.2) 38 | return Index(encodedOffset: offset).samePosition(in: utf16) 39 | #else 40 | return UTF16View.Index(offset).samePosition(in: self) 41 | #endif 42 | } 43 | 44 | func utf16Offset(fromIndex index: String.Index) -> Int { 45 | #if swift(>=3.2) 46 | return index.encodedOffset 47 | #else 48 | return utf16.startIndex.distance(to: index.samePosition(in: utf16)) 49 | #endif 50 | } 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/EmptyPatternRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EmptyPatternRegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/4. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class EmptyPatternRegexTests: RegexTests { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | 17 | regex = "(:?)".asRegex 18 | s = "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\n Link™" 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/EmptyStringRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EmptyStringRegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/5. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class EmptyStringRegexTests: RegexTests { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | 17 | s = "" 18 | regex = "()".asRegex 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/LLRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LLRegexTests.swift 3 | // LLRegexTests 4 | // 5 | // Created by Rock Young on 2017/5/31. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LLRegex 11 | 12 | class LLRegexTests: XCTestCase { 13 | 14 | var tmRegex: Regex! 15 | var zeldaRegex: Regex! 16 | var s: String = "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™" 17 | 18 | override func setUp() { 19 | super.setUp() 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | tmRegex = Regex("((\\S)(\\S*)(\\S))™") 23 | zeldaRegex = Regex("(zelda|link)(™)?", options: [.caseInsensitive]) 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testMatchFirst() { 32 | 33 | XCTAssertEqual(tmRegex.matches(in: s).first?.matched, "😊😾LL™") 34 | XCTAssertEqual(zeldaRegex.matches(in: s).first?.matched, "Zelda™") 35 | 36 | } 37 | 38 | func testMatchAll() { 39 | 40 | XCTAssertEqual(tmRegex.matches(in: s).all.map { $0.matched }, ["😊😾LL™", "ゼルダ™", "Zelda™", "ll™", "塞尔达™", "Link™"]) 41 | XCTAssertEqual(zeldaRegex.matches(in: s).all.count, 3) 42 | XCTAssertEqual(zeldaRegex.matches(in: s).all[1].matched, "zelda") 43 | } 44 | 45 | func testMatchSequence() { 46 | 47 | XCTAssertEqual(tmRegex.matches(in: s).prefix(2).map { $0.matched }, ["😊😾LL™", "ゼルダ™"]) 48 | XCTAssertEqual(zeldaRegex.matches(in: s).suffix(2).map { $0.matched }, ["zelda", "Link™"]) 49 | 50 | for (idx, _) in tmRegex.matches(in: s).dropFirst().enumerated() { 51 | XCTAssertTrue(idx < 5) 52 | } 53 | } 54 | 55 | func testMatchRange() { 56 | 57 | var range: Range = 0..<5 58 | 59 | XCTAssertEqual(tmRegex.matches(in: s, range: s.charactersRange(offsetBy: range)).all.count, 1) 60 | 61 | range = 0..<4 62 | XCTAssertEqual(tmRegex.matches(in: s, range: s.charactersRange(offsetBy: range)).all.count, 0) 63 | 64 | range = 20..<73 65 | XCTAssertEqual(tmRegex.matches(in: s, range: s.charactersRange(offsetBy: range)).all.count, 4) 66 | 67 | range = 20..<72 68 | XCTAssertEqual(tmRegex.matches(in: s, range: s.charactersRange(offsetBy: range)).all.count, 3) 69 | } 70 | 71 | 72 | func testReplaceFirst() { 73 | 74 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, replacement: .keep), s) 75 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, replacement: .stop), s) 76 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, replacement: .remove), "abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 77 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, replacement: .replaceWithString("$0$1$2$3 ")), "$0$1$2$3 abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 78 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, replacement: .replaceWithTemplate("$0$1$2$3 ")), "😊😾LL™😊😾LL😊😾L abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 79 | 80 | } 81 | 82 | func testRepalceAll() { 83 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, replacement: .keep), s) 84 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, replacement: .stop), s) 85 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, replacement: .remove), "abc 1™ <😍 の伝説 is so awesome!>\n< 最高 3>😃zelda\r\n ") 86 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, replacement: .replaceWithString("($4$3$2)")), "($4$3$2)abc 1™ <😍 ($4$3$2)の伝説 ($4$3$2) is so awesome!>\n($4$3$2)< ($4$3$2)最高 3>😃zelda\r\n ($4$3$2)") 87 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, replacement: .replaceWithTemplate("($4$3$2)")), "(L😾L😊)abc 1™ <😍 (ダルゼ)の伝説 (aeldZ) is so awesome!>\n(ll)< (达尔塞)最高 3>😃zelda\r\n (kinL)") 88 | } 89 | 90 | func testReplaceCustom() { 91 | 92 | let result = tmRegex.replacingMatches(in: s) { (idx, match) -> Match.Replacing in 93 | 94 | return .replaceWithTemplate("(\(idx + 1): $1, \(String(match.groups[1].matched.characters.reversed())))") 95 | } 96 | 97 | XCTAssertEqual(result, "(1: 😊😾LL, LL😾😊)abc 1™ <😍 (2: ゼルダ, ダルゼ)の伝説 (3: Zelda, adleZ) is so awesome!>\n(4: ll, ll)< (5: 塞尔达, 达尔塞)最高 3>😃zelda\r\n (6: Link, kniL)") 98 | } 99 | 100 | func testReplaceRange() { 101 | 102 | XCTAssertEqual(tmRegex.replacingFirstMatch(in: s, range: s.charactersRange(offsetBy: 0..<4), replacement: .remove), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 103 | XCTAssertEqual(tmRegex.replacingAllMatches(in: s, options: [], range: s.range(of: "™")!.upperBound..\n😸< 😸最高 3>😃zelda\r\n 😸") 104 | 105 | let result = tmRegex.replacingMatches(in: s, range: s.startIndex.. Match.Replacing in 106 | 107 | return .replaceWithTemplate("(\(idx + 1): $1, \(String(match.groups[1].matched.characters.reversed())))") 108 | } 109 | 110 | XCTAssertEqual(result, "(1: 😊😾LL, LL😾😊)abc 1™ <😍 (2: ゼルダ, ダルゼ)の伝説 (3: Zelda, adleZ) is so awesome!>\n(4: ll, ll)< (5: 塞尔达, 达尔塞)最高 3>😃zelda\r\n Link™") 111 | } 112 | 113 | func testMatch() { 114 | 115 | let all = tmRegex.matches(in: s).all 116 | 117 | XCTAssertEqual(all[0].range, s.range(of: "😊😾LL™")) 118 | XCTAssertEqual(all[0].matched, "😊😾LL™") 119 | XCTAssertEqual(all[0].groups[0].matched, "😊😾LL™") 120 | XCTAssertEqual(all[0].groups[1].matched, "😊😾LL") 121 | XCTAssertEqual(all[0].groups[2].matched, "😊") 122 | XCTAssertEqual(all[0].groups[3].matched, "😾L") 123 | XCTAssertEqual(all[0].groups[4].matched, "L") 124 | 125 | XCTAssertEqual(all[3].matched, "ll™") 126 | XCTAssertEqual(all[3].groups[0].matched, "ll™") 127 | XCTAssertEqual(all[3].groups[1].matched, "ll") 128 | XCTAssertEqual(all[3].groups[2].matched, "l") 129 | XCTAssertEqual(all[3].groups[3].matched, "") 130 | XCTAssertEqual(all[3].groups[4].matched, "l") 131 | 132 | let notFoundGroup = zeldaRegex.matches(in: s).all[1].groups[2] 133 | XCTAssertEqual(notFoundGroup.matched, "") 134 | XCTAssertNil(notFoundGroup.range) 135 | } 136 | 137 | func testRegex() { 138 | 139 | let regex1 = Regex("\\d+") 140 | let regex2 = Regex("\\d+") 141 | let regex3 = Regex("\\d+", options: [.caseInsensitive]) 142 | let regex4 = Regex("\\D+", options: [.caseInsensitive]) 143 | 144 | XCTAssertEqual(regex1, regex2) 145 | XCTAssertNotEqual(regex1, regex3) 146 | XCTAssertNotEqual(regex3, regex4) 147 | 148 | XCTAssertEqual(regex1.hashValue, regex2.hashValue) 149 | XCTAssertNotEqual(regex1.hashValue, regex3.hashValue) 150 | XCTAssertNotEqual(regex3.hashValue, regex4.hashValue) 151 | 152 | XCTAssertNil(try? Regex(pattern: "(\\d")) 153 | XCTAssertNotNil(try? Regex(pattern: "()")) 154 | } 155 | 156 | func testPattern() { 157 | 158 | XCTAssertEqual(zeldaRegex.pattern, "(zelda|link)(™)?") 159 | 160 | XCTAssertThrowsError(try zeldaRegex.setPattern("")) 161 | 162 | XCTAssertNoThrow(try zeldaRegex.setPattern("\\d+")) 163 | 164 | XCTAssertEqual(zeldaRegex.options, [.caseInsensitive]) 165 | 166 | } 167 | 168 | func testOptions() { 169 | 170 | XCTAssertEqual(zeldaRegex.options, [.caseInsensitive]) 171 | 172 | zeldaRegex.options.remove(.caseInsensitive) 173 | 174 | XCTAssertEqual(zeldaRegex.options, []) 175 | XCTAssertEqual(zeldaRegex.pattern, "(zelda|link)(™)?") 176 | 177 | zeldaRegex.options.insert(.namedCaptureGroups) 178 | XCTAssertEqual(zeldaRegex.options, [.namedCaptureGroups]) 179 | XCTAssertEqual(zeldaRegex.pattern, "(zelda|link)(™)?") 180 | 181 | zeldaRegex.options = [.allowCommentsAndWhitespace, .anchorsMatchLines, .namedCaptureGroups] 182 | XCTAssertEqual(zeldaRegex.options, [.allowCommentsAndWhitespace, .anchorsMatchLines, .namedCaptureGroups]) 183 | } 184 | 185 | func testRegularExpression() { 186 | 187 | tmRegex.regularExpression = try! NSRegularExpression(pattern: "\\d+", options: [.allowCommentsAndWhitespace, .useUnixLineSeparators]) 188 | 189 | XCTAssertEqual(tmRegex.pattern, "\\d+") 190 | XCTAssertEqual(tmRegex.options, [.allowCommentsAndWhitespace, .useUnixLineSeparators]) 191 | } 192 | 193 | #if !SWIFT_PACKAGE 194 | func testRegexPerformance() { 195 | let content: String = try! String(contentsOf: Bundle(for: LLRegexTests.self).url(forResource: "LargeContent", withExtension: "txt")!) 196 | 197 | let pattern: String = "\\s*0x([A-F0-9]+)" 198 | 199 | let regex: Regex = try! Regex(pattern: pattern, options: [.caseInsensitive, .anchorsMatchLines]) 200 | let nsRegex: NSRegularExpression = try! NSRegularExpression(pattern: pattern, options: [NSRegularExpression.Options.caseInsensitive, NSRegularExpression.Options.anchorsMatchLines]) 201 | 202 | var result: [Double] = [] 203 | 204 | for _ in 0..<100 { 205 | var date: Date 206 | 207 | date = Date() 208 | let match1 = regex.matches(in: content).all.map { ($0.groups[1].matched) } 209 | let interval1 = Date().timeIntervalSince(date) 210 | 211 | date = Date() 212 | let nsContent: NSString = content as NSString 213 | let match2 = nsRegex.matches(in: content, range: NSRange(location: 0, length: nsContent.length)).map({ result -> String in 214 | 215 | let group: NSRange 216 | #if swift(>=4) 217 | group = result.range(at: 1) 218 | #else 219 | group = result.rangeAt(1) 220 | #endif 221 | 222 | return (nsContent.substring(with: group) as String) }) 223 | let interval2 = Date().timeIntervalSince(date) 224 | result.append(interval1 / interval2) 225 | 226 | XCTAssertEqual(match1, match2) 227 | } 228 | 229 | let ratio = result.reduce(0, +) / Double(result.count) 230 | Swift.print("avg: \(ratio)") 231 | 232 | XCTAssertLessThan(ratio, 2) 233 | } 234 | #endif 235 | 236 | func testRegexOptions() { 237 | var regex = Regex("\\d+", options: [.caseInsensitive, .allowCommentsAndWhitespace, .anchorsMatchLines, .dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 238 | 239 | XCTAssertEqual(regex.options, [.caseInsensitive, .allowCommentsAndWhitespace, .anchorsMatchLines, . 240 | dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 241 | 242 | regex.options.remove(.caseInsensitive) 243 | XCTAssertEqual(regex.options, [.allowCommentsAndWhitespace, .anchorsMatchLines, . 244 | dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 245 | 246 | XCTAssertEqual(regex.options.toAdapted(), [.allowCommentsAndWhitespace, .anchorsMatchLines, . 247 | dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 248 | 249 | try! regex.setPattern("\\d*") 250 | XCTAssertEqual(regex.options, [.allowCommentsAndWhitespace, .anchorsMatchLines, . 251 | dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 252 | 253 | regex = Regex(regularExpression: try! NSRegularExpression(pattern: "\\d+", options: [.caseInsensitive, .allowCommentsAndWhitespace, .anchorsMatchLines, .dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators])) 254 | XCTAssertEqual(regex.options, [.caseInsensitive, .allowCommentsAndWhitespace, .anchorsMatchLines, .dotMatchesLineSeparators, .ignoreMetacharacters, .useUnicodeWordBoundaries, .useUnixLineSeparators]) 255 | 256 | regex.regularExpression = try! NSRegularExpression(pattern: "\\d*", options: .caseInsensitive) 257 | XCTAssertEqual(regex.options, .caseInsensitive) 258 | 259 | regex = Regex("\\d+", options: [.caseInsensitive, .namedCaptureGroups]) 260 | XCTAssertEqual(regex.options, [.caseInsensitive, .namedCaptureGroups]) 261 | 262 | XCTAssertEqual(regex.regularExpression.options, [.caseInsensitive]) 263 | 264 | } 265 | 266 | func testMatchOptions() { 267 | 268 | var options: Match.Options = [.anchored, .withTransparentBounds, .withoutAnchoringBounds] 269 | 270 | XCTAssertEqual(options, [.anchored, .withTransparentBounds, .withoutAnchoringBounds]) 271 | 272 | XCTAssertEqual(options.toAdapted(), [.anchored, .withTransparentBounds, .withoutAnchoringBounds]) 273 | 274 | options = [] 275 | XCTAssertEqual(options.toAdapted(), []) 276 | 277 | XCTAssertEqual(options, Match.Options(adapted: [.reportProgress, .reportCompletion])) 278 | } 279 | } 280 | 281 | 282 | 283 | extension String { 284 | 285 | func charactersRange(offsetBy range: Range) -> Range { 286 | return index(startIndex, offsetBy: range.lowerBound)..abc)", expectedGroupsCount: 1)!, ["name": 1]) 31 | 32 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?abc)-(?\\d+)", expectedGroupsCount: 2)!, ["name": 1, "number1": 2]) 33 | 34 | XCTAssertEqual(extractNamedCaptureGroups(in: "(\\d)(?abc)-(?\\d+)", expectedGroupsCount: 3)!, ["name": 2, "number1": 3]) 35 | 36 | XCTAssertEqual(extractNamedCaptureGroups(in: "(\\d(?abc)-(?\\d+))", expectedGroupsCount: 3)!, ["name": 2, "number1": 3]) 37 | 38 | XCTAssertEqual(extractNamedCaptureGroups(in: "(\\d(?abc((?\\d+)1)))", expectedGroupsCount: 4)!, ["name": 2, "number1": 4]) 39 | 40 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?:\\d)", expectedGroupsCount: 0)!, [:]) 41 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?)", expectedGroupsCount: 0)!, [:]) 42 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?<=)", expectedGroupsCount: 0)!, [:]) 43 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?!)", expectedGroupsCount: 0)!, [:]) 44 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?=)", expectedGroupsCount: 0)!, [:]) 45 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?#)", expectedGroupsCount: 0)!, [:]) 46 | XCTAssertEqual(extractNamedCaptureGroups(in: "(?>)", expectedGroupsCount: 0)!, [:]) 47 | 48 | XCTAssertEqual(extractNamedCaptureGroups(in: "\\(\\)", expectedGroupsCount: 0)!, [:]) 49 | XCTAssertEqual(extractNamedCaptureGroups(in: "\\\\()", expectedGroupsCount: 1)!, [:]) 50 | XCTAssertEqual(extractNamedCaptureGroups(in: "\\(?\\)", expectedGroupsCount: 0)!, [:]) 51 | XCTAssertEqual(extractNamedCaptureGroups(in: "\\\\(?)", expectedGroupsCount: 1)!, ["name": 1]) 52 | } 53 | 54 | func testNamdCaptureGroupsTypes() { 55 | 56 | guard #available(iOS 9, *) else { return } 57 | 58 | XCTAssertEqual(Regex("\\d", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 59 | XCTAssertEqual(Regex("()", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 60 | XCTAssertEqual(Regex("(?abc)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 1) 61 | XCTAssertEqual(Regex("(?abc)-(?\\d+)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 62 | XCTAssertEqual(Regex("(\\d)(?abc)-(?\\d+)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 63 | XCTAssertEqual(Regex("(\\d(?abc)-(?\\d+))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 64 | XCTAssertEqual(Regex("(\\d(?abc((?\\d+)1)))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 65 | XCTAssertEqual(Regex("(\\d(?abc((?\\d+)1)))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 66 | XCTAssertEqual(Regex("(\\d(?abc((?\\d+)1)))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 67 | XCTAssertEqual(Regex("(\\d(?abc((?\\d+)1)))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 68 | XCTAssertEqual(Regex("(\\d(?abc((?\\d+)1)))", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 2) 69 | 70 | XCTAssertEqual(Regex("(?:\\d)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 71 | XCTAssertEqual(Regex("(?)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 72 | XCTAssertEqual(Regex("(?<=)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 73 | XCTAssertEqual(Regex("(?!)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 74 | XCTAssertEqual(Regex("(?=)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 75 | XCTAssertEqual(Regex("(?#)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 76 | XCTAssertEqual(Regex("(?>)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 77 | 78 | XCTAssertEqual(Regex("\\(\\)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 79 | XCTAssertEqual(Regex("\\\\()", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 80 | XCTAssertEqual(Regex("\\(?\\)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 0) 81 | XCTAssertEqual(Regex("\\\\(?)", options: [.namedCaptureGroups]).namedCaptureGroupsInfo!.count, 1) 82 | } 83 | 84 | func testNamdCaptureGroups() { 85 | 86 | guard #available(iOS 9, *) else { return } 87 | 88 | let s = "123 normal NAMED (Nested) atomic non-capture 456" 89 | let regex = Regex("(?#comment)(?named) (\\((?nested)\\)) (?>atomic) (?:non-capture) (?=456)(?!a)", options: [.namedCaptureGroups]) 90 | 91 | XCTAssertEqual(regex.namedCaptureGroupsInfo!, ["name": 2, "nested": 4]) 92 | 93 | let match = regex.matches(in: s).first! 94 | 95 | XCTAssertEqual(match.groups["name"]!.matched, "NAMED") 96 | XCTAssertEqual(match.groups["nested"]!.matched, "Nested") 97 | XCTAssertNil(match.groups[""]) 98 | } 99 | 100 | func testReplacement() { 101 | 102 | guard #available(iOS 9, *) else { return } 103 | 104 | let date = "1978-12-24" 105 | let named = Regex("((?\\d+)-(?\\d+)-(?\\d+))", options: .namedCaptureGroups) 106 | let nonNamed = Regex("((?\\d+)-(?\\d+)-(?\\d+))") 107 | let namedMatch = named.matches(in: date).first! 108 | let nonNamedMatch = nonNamed.matches(in: date).first! 109 | 110 | XCTAssertEqual(namedMatch.replacement(withTemplate: "$2$3$4"), "19781224") 111 | XCTAssertEqual(namedMatch.replacement(withTemplate: "${year}${month}${day}"), "19781224") 112 | XCTAssertEqual(namedMatch.replacement(withTemplate: "\\${year}${month}\\\\${day}"), "${year}12\\24") 113 | XCTAssertEqual(namedMatch.replacement(withTemplate: "$9${unknown}!"), "!") 114 | 115 | XCTAssertEqual(nonNamedMatch.replacement(withTemplate: "$2$3$4"), "19781224") 116 | XCTAssertEqual(nonNamedMatch.replacement(withTemplate: "${year}${month}${day}"), "${year}${month}${day}") 117 | XCTAssertEqual(nonNamedMatch.replacement(withTemplate: "$9${unknown}!"), "${unknown}!") 118 | 119 | } 120 | 121 | func testComment() { 122 | 123 | guard #available(iOS 9, *) else { return } 124 | 125 | let s = "1234567890" 126 | let regex = Regex("(\\d{1,2})(?\\d)(?x) # (\\d+)", options: .namedCaptureGroups) 127 | 128 | XCTAssertNil(regex.namedCaptureGroupsInfo) 129 | XCTAssertEqual(regex.matches(in: s).first!.replacement(withTemplate: "$1${suffix}"), "12") 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/RegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/4. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LLRegex 11 | 12 | class RegexTests: XCTestCase { 13 | 14 | var s: String! 15 | var regex: Regex! 16 | var template: String! 17 | var matchOptions: Match.Options! 18 | 19 | override func setUp() { 20 | super.setUp() 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | 23 | s = "091-9320-32432432" 24 | regex = "\\d+".asRegex 25 | template = "($0)" 26 | matchOptions = [] 27 | } 28 | 29 | override func tearDown() { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | super.tearDown() 32 | } 33 | 34 | func testMatch() { 35 | 36 | let expected = regex.regularExpression.matches(in: s, options: matchOptions.toAdapted(), range: s.nsRange).flatMap { result in 37 | return result.range.toRange(in: s).map({ String(s[$0]) }) 38 | } 39 | 40 | let result = regex.matches(in: s, options: matchOptions).map { $0.matched } 41 | 42 | XCTAssertEqual(result, expected) 43 | 44 | } 45 | 46 | func testRaplace() { 47 | 48 | let expected = regex.regularExpression.stringByReplacingMatches(in: s, options: matchOptions.toAdapted(), range: s.nsRange, withTemplate: template) 49 | 50 | let result = regex.replacingAllMatches(in: s, options: matchOptions, replacement: .replaceWithTemplate(template)) 51 | 52 | XCTAssertEqual(result, expected) 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/ReturnRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReturnRegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/5. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LLRegex 11 | 12 | class ReturnRegexTests: RegexTests { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | s = "\n \r\n \r" 19 | regex = "\r".asRegex 20 | } 21 | 22 | override func tearDown() { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | super.tearDown() 25 | } 26 | 27 | override func testMatch() { 28 | 29 | let expected = regex.regularExpression.numberOfMatches(in: s, options: matchOptions.toAdapted(), range: s.nsRange) 30 | let result = regex.matches(in: s, options: matchOptions).all.count 31 | 32 | #if swift(>=3.2) 33 | XCTAssertEqual(result, expected) 34 | XCTAssertEqual(result, 2) 35 | XCTAssertEqual(regex.matches(in: s, options: matchOptions).first?.matched, "\r") 36 | #else 37 | XCTAssertEqual(result, expected - 1) 38 | XCTAssertEqual(result, 1) 39 | #endif 40 | } 41 | 42 | override func testRaplace() { 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/StringRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StringRegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/3. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import LLRegex 11 | 12 | class StringRegexTests: XCTestCase { 13 | 14 | var s: String = "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™" 15 | 16 | override func setUp() { 17 | super.setUp() 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | func testReplaceFirst() { 27 | 28 | XCTAssertEqual(s.replacingFirst("zelda", with: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃$1\r\n Link™") 29 | XCTAssertEqual(s.replacingFirst(pattern: "(z)elda", withTemplate: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 30 | XCTAssertEqual(s.replacingFirst(pattern: Regex("(z)elda", options: [.caseInsensitive]), withTemplate: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Z™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 31 | 32 | XCTAssertEqual(s.replacingFirst(pattern: Regex("(z)elda", options: [.caseInsensitive]), in: s.range(of: "Zelda™")!.upperBound..\nll™< 塞尔达™最高 3>😃z\r\n Link™") 33 | 34 | var result = s 35 | 36 | result.replaceFirst("zelda", with: "$1") 37 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃$1\r\n Link™") 38 | 39 | result = s 40 | result.replaceFirst(pattern: "(z)elda", withTemplate: "$1") 41 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 42 | 43 | result = s 44 | result.replaceFirst(pattern: Regex("(z)elda", options: [.caseInsensitive]), withTemplate: "$1") 45 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Z™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\r\n Link™") 46 | 47 | 48 | result = s 49 | result.replaceFirst(pattern: Regex("(z)elda", options: [.caseInsensitive]), in: s.range(of: "Zelda™")!.upperBound..\nll™< 塞尔达™最高 3>😃z\r\n Link™") 51 | } 52 | 53 | func testRepalceAll() { 54 | 55 | XCTAssertEqual(s.replacingAll("zelda", with: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃$1\r\n Link™") 56 | XCTAssertEqual(s.replacingAll(pattern: "(z)elda", withTemplate: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 57 | XCTAssertEqual(s.replacingAll(pattern: Regex("(z)elda", options: [.caseInsensitive]), withTemplate: "$1"), "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Z™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 58 | 59 | XCTAssertEqual(s.replacingAll(pattern: Regex("(z)elda", options: [.caseInsensitive]), in: s.range(of: "Zelda™")!.upperBound..\nll™< 塞尔达™最高 3>😃z\r\n Link™") 60 | 61 | var result = s 62 | 63 | result.replaceAll("zelda", with: "$1") 64 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃$1\r\n Link™") 65 | 66 | result = s 67 | result.replaceAll(pattern: "(z)elda", withTemplate: "$1") 68 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 69 | 70 | result = s 71 | result.replaceAll(pattern: Regex("(z)elda", options: [.caseInsensitive]), withTemplate: "$1") 72 | XCTAssertEqual(result, "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Z™ is so awesome!>\nll™< 塞尔达™最高 3>😃z\r\n Link™") 73 | 74 | 75 | result = s 76 | result.replaceAll(pattern: Regex("(z)elda", options: [.caseInsensitive]), in: s.range(of: "Zelda™")!.upperBound..\nll™< 塞尔达™最高 3>😃z\r\n Link™") 78 | } 79 | 80 | func testMatching() { 81 | 82 | XCTAssertTrue("a1".isMatching("a\\d+")) 83 | XCTAssertFalse("A1".isMatching("a\\d+")) 84 | XCTAssertFalse("a".isMatching("a\\d+")) 85 | XCTAssertFalse("a1b".isMatching("a\\d+")) 86 | XCTAssertFalse("1".isMatching("a\\d+")) 87 | 88 | XCTAssertTrue("a1".isMatching("a\\d+", entirely: false)) 89 | XCTAssertFalse("A1".isMatching("a\\d+", entirely: false)) 90 | XCTAssertFalse("a".isMatching("a\\d+", entirely: false)) 91 | XCTAssertTrue("a1b".isMatching("a\\d+", entirely: false)) 92 | XCTAssertFalse("1".isMatching("a\\d+", entirely: false)) 93 | 94 | let regex1 = Regex("a\\d+", options: [.caseInsensitive]) 95 | 96 | XCTAssertTrue("a1".isMatching(regex1)) 97 | XCTAssertTrue("A1".isMatching(regex1)) 98 | XCTAssertFalse("a".isMatching(regex1)) 99 | XCTAssertFalse("a1b".isMatching(regex1)) 100 | XCTAssertFalse("1".isMatching(regex1)) 101 | 102 | XCTAssertTrue("a1".isMatching(regex1, entirely: false)) 103 | XCTAssertTrue("A1".isMatching(regex1, entirely: false)) 104 | XCTAssertFalse("a".isMatching(regex1, entirely: false)) 105 | XCTAssertTrue("a1b".isMatching(regex1, entirely: false)) 106 | XCTAssertFalse("1".isMatching(regex1, entirely: false)) 107 | 108 | } 109 | 110 | func testSplit() { 111 | 112 | let s: String = "0a12b234c34560" 113 | 114 | XCTAssertEqual(s.split(seperator: "3"), ["0a12b2", "4c", "4560"]) 115 | XCTAssertEqual(s.split(seperator: "3", maxSplits: 0), ["0a12b234c34560"]) 116 | XCTAssertEqual(s.split(seperator: "3", maxSplits: 1), ["0a12b2", "4c34560"]) 117 | 118 | XCTAssertEqual(s.split(seperator: "0"), ["a12b234c3456"]) 119 | XCTAssertEqual(s.split(seperator: "0", omittingEmptyString: false), ["", "a12b234c3456", ""]) 120 | XCTAssertEqual(s.split(seperator: "0", maxSplits: 0, omittingEmptyString: false), ["0a12b234c34560"]) 121 | XCTAssertEqual(s.split(seperator: "0", maxSplits: 1, omittingEmptyString: false), ["", "a12b234c34560"]) 122 | 123 | XCTAssertEqual("".split(seperator: "0"), []) 124 | XCTAssertEqual("".split(seperator: "0", omittingEmptyString: false), [""]) 125 | 126 | XCTAssertEqual("ab".split(seperator: ""), ["a", "b"]) 127 | XCTAssertEqual("ab".split(seperator: "", omittingEmptyString: false), ["", "a", "b", ""]) 128 | 129 | XCTAssertEqual("".split(seperator: ""), []) 130 | XCTAssertEqual("".split(seperator: "", omittingEmptyString: false), ["", ""]) 131 | 132 | let regex = Regex("\\d+") 133 | 134 | XCTAssertEqual(s.split(seperator: regex), ["a", "b", "c"]) 135 | XCTAssertEqual(s.split(seperator: regex, maxSplits: 0), ["0a12b234c34560"]) 136 | XCTAssertEqual(s.split(seperator: regex, maxSplits: 1), ["a12b234c34560"]) 137 | 138 | XCTAssertEqual(s.split(seperator: regex, omittingEmptyString: false), ["", "a", "b", "c", ""]) 139 | XCTAssertEqual(s.split(seperator: regex, maxSplits: 0, omittingEmptyString: false), ["0a12b234c34560"]) 140 | XCTAssertEqual(s.split(seperator: regex, maxSplits: 1, omittingEmptyString: false), ["", "a12b234c34560"]) 141 | 142 | XCTAssertEqual(s.split(seperator: regex.pattern), ["a", "b", "c"]) 143 | XCTAssertEqual(s.split(seperator: regex.pattern, maxSplits: 0), ["0a12b234c34560"]) 144 | XCTAssertEqual(s.split(seperator: regex.pattern, maxSplits: 1), ["a12b234c34560"]) 145 | 146 | XCTAssertEqual(s.split(seperator: regex.pattern, omittingEmptyString: false), ["", "a", "b", "c", ""]) 147 | XCTAssertEqual(s.split(seperator: regex.pattern, maxSplits: 0, omittingEmptyString: false), ["0a12b234c34560"]) 148 | XCTAssertEqual(s.split(seperator: regex.pattern, maxSplits: 1, omittingEmptyString: false), ["", "a12b234c34560"]) 149 | 150 | XCTAssertEqual("\\da".split(seperator: "\\d".escapedAsPattern()), ["a"]) 151 | XCTAssertEqual("\\da".split(seperator: "(\\d"), ["\\da"]) 152 | 153 | 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /Tests/LLRegexTests/WordBRegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WordBRegexTests.swift 3 | // LLRegex 4 | // 5 | // Created by Rock Young on 2017/6/4. 6 | // Copyright © 2017年 Rock Young. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class WordBRegexTests: RegexTests { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | // Put setup code here. This method is called before the invocation of each test method in the class. 16 | 17 | regex = "\\B".asRegex 18 | s = "😊😾LL™abc 1™ <😍 ゼルダ™の伝説 Zelda™ is so awesome!>\nll™< 塞尔达™最高 3>😃zelda\n Link™" 19 | } 20 | 21 | override func tearDown() { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | super.tearDown() 24 | } 25 | 26 | } 27 | --------------------------------------------------------------------------------