├── .gitignore ├── .swift-version ├── .travis.yml ├── LICENSE ├── PySwiftyRegex.podspec ├── PySwiftyRegex.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── PySwiftyRegex.xcscheme ├── PySwiftyRegex ├── Info.plist ├── PySwiftyRegex.h └── PySwiftyRegex.swift ├── PySwiftyRegexTests ├── Info.plist ├── ReMatchObjectTests.swift ├── ReRegexObjectTests.swift ├── ReTests.swift └── TestHelpers.swift ├── README-ja.md ├── README-ko.md ├── README-zh.md └── README.md /.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 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # OSX 46 | .DS_Store 47 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | os: osx 4 | osx_image: xcode10.3 5 | 6 | env: 7 | global: 8 | - XCODEPROJ="PySwiftyRegex.xcodeproj" 9 | - SCHEME="PySwiftyRegex" 10 | matrix: 11 | - DESTINATION="platform=OS X,arch=x86_64" SDK="macosx" ACTION="test" 12 | - DESTINATION="platform=iOS Simulator,name=iPhone X" SDK="iphonesimulator" ACTION="test" 13 | - DESTINATION="platform=tvOS Simulator,name=Apple TV 4K" SDK="appletvsimulator" ACTION="test" 14 | - DESTINATION="name=Apple Watch Series 4 - 40mm" SDK="watchsimulator" ACTION="build" 15 | 16 | script: 17 | - xcode-select -p 18 | - xcodebuild -project "$XCODEPROJ" -scheme "$SCHEME" -destination "$DESTINATION" -sdk $SDK $ACTION 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ce Zheng 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /PySwiftyRegex.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "PySwiftyRegex" 3 | s.version = "3.0.0" 4 | s.license = "MIT" 5 | s.summary = "Easily deal with Regex in Swift in a Pythonic way" 6 | s.homepage = "https://github.com/cezheng/PySwiftyRegex" 7 | s.social_media_url = "https://twitter.com/AdamoCheng" 8 | s.author = { "Ce Zheng" => "cezheng.cs@gmail.com" } 9 | s.source = { :git => "https://github.com/cezheng/PySwiftyRegex.git", :tag => s.version } 10 | 11 | s.ios.deployment_target = "8.0" 12 | s.osx.deployment_target = "10.9" 13 | s.watchos.deployment_target = "2.0" 14 | s.tvos.deployment_target = "9.0" 15 | 16 | s.source_files = "PySwiftyRegex/*.swift" 17 | 18 | s.requires_arc = true 19 | end 20 | -------------------------------------------------------------------------------- /PySwiftyRegex.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0CEBDD2E1B39B8C4003A40BB /* PySwiftyRegex.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CEBDD241B39B8C3003A40BB /* PySwiftyRegex.framework */; }; 11 | 0CEBDD3B1B39BAC3003A40BB /* PySwiftyRegex.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CEBDCE11B39B2FB003A40BB /* PySwiftyRegex.h */; settings = {ATTRIBUTES = (Public, ); }; }; 12 | 0CEBDD3C1B39C54B003A40BB /* ReRegexObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CEBDCED1B39B2FC003A40BB /* ReRegexObjectTests.swift */; }; 13 | 0CEBDD3D1B39C54B003A40BB /* ReMatchObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CEBDCFA1B39B48C003A40BB /* ReMatchObjectTests.swift */; }; 14 | 0CEBDD3E1B39C5EC003A40BB /* PySwiftyRegex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0CEBDCF81B39B312003A40BB /* PySwiftyRegex.swift */; }; 15 | 795691DB1C74A9B9002B1CA4 /* ReTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C383C3A1B50CFF5008837A8 /* ReTests.swift */; }; 16 | 795691DE1C74AACB002B1CA4 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 795691DC1C74AACB002B1CA4 /* TestHelpers.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXContainerItemProxy section */ 20 | 0CEBDD2F1B39B8C4003A40BB /* PBXContainerItemProxy */ = { 21 | isa = PBXContainerItemProxy; 22 | containerPortal = 0CEBDCD51B39B2FB003A40BB /* Project object */; 23 | proxyType = 1; 24 | remoteGlobalIDString = 0CEBDD231B39B8C3003A40BB; 25 | remoteInfo = PySwiftyRegex; 26 | }; 27 | /* End PBXContainerItemProxy section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 0C383C3A1B50CFF5008837A8 /* ReTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReTests.swift; sourceTree = ""; }; 31 | 0CEBDCE11B39B2FB003A40BB /* PySwiftyRegex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PySwiftyRegex.h; sourceTree = ""; }; 32 | 0CEBDCE31B39B2FB003A40BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 0CEBDCED1B39B2FC003A40BB /* ReRegexObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReRegexObjectTests.swift; sourceTree = ""; }; 34 | 0CEBDCEF1B39B2FC003A40BB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 35 | 0CEBDCF81B39B312003A40BB /* PySwiftyRegex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PySwiftyRegex.swift; sourceTree = ""; }; 36 | 0CEBDCFA1B39B48C003A40BB /* ReMatchObjectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReMatchObjectTests.swift; sourceTree = ""; }; 37 | 0CEBDD241B39B8C3003A40BB /* PySwiftyRegex.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PySwiftyRegex.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 38 | 0CEBDD2D1B39B8C4003A40BB /* PySwiftyRegexTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PySwiftyRegexTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 795691DC1C74AACB002B1CA4 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 0CEBDD201B39B8C3003A40BB /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | 0CEBDD2A1B39B8C4003A40BB /* Frameworks */ = { 51 | isa = PBXFrameworksBuildPhase; 52 | buildActionMask = 2147483647; 53 | files = ( 54 | 0CEBDD2E1B39B8C4003A40BB /* PySwiftyRegex.framework in Frameworks */, 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | /* End PBXFrameworksBuildPhase section */ 59 | 60 | /* Begin PBXGroup section */ 61 | 0CEBDCD41B39B2FB003A40BB = { 62 | isa = PBXGroup; 63 | children = ( 64 | 0CEBDCE01B39B2FB003A40BB /* PySwiftyRegex */, 65 | 0CEBDCEC1B39B2FC003A40BB /* PySwiftyRegexTests */, 66 | 0CEBDCDF1B39B2FB003A40BB /* Products */, 67 | ); 68 | sourceTree = ""; 69 | }; 70 | 0CEBDCDF1B39B2FB003A40BB /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 0CEBDD241B39B8C3003A40BB /* PySwiftyRegex.framework */, 74 | 0CEBDD2D1B39B8C4003A40BB /* PySwiftyRegexTests.xctest */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | 0CEBDCE01B39B2FB003A40BB /* PySwiftyRegex */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 0CEBDCE11B39B2FB003A40BB /* PySwiftyRegex.h */, 83 | 0CEBDCF81B39B312003A40BB /* PySwiftyRegex.swift */, 84 | 0CEBDCE31B39B2FB003A40BB /* Info.plist */, 85 | ); 86 | path = PySwiftyRegex; 87 | sourceTree = ""; 88 | }; 89 | 0CEBDCEC1B39B2FC003A40BB /* PySwiftyRegexTests */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 0C383C3A1B50CFF5008837A8 /* ReTests.swift */, 93 | 0CEBDCED1B39B2FC003A40BB /* ReRegexObjectTests.swift */, 94 | 0CEBDCFA1B39B48C003A40BB /* ReMatchObjectTests.swift */, 95 | 0CEBDCEF1B39B2FC003A40BB /* Info.plist */, 96 | 795691DC1C74AACB002B1CA4 /* TestHelpers.swift */, 97 | ); 98 | path = PySwiftyRegexTests; 99 | sourceTree = ""; 100 | }; 101 | /* End PBXGroup section */ 102 | 103 | /* Begin PBXHeadersBuildPhase section */ 104 | 0CEBDD211B39B8C3003A40BB /* Headers */ = { 105 | isa = PBXHeadersBuildPhase; 106 | buildActionMask = 2147483647; 107 | files = ( 108 | 0CEBDD3B1B39BAC3003A40BB /* PySwiftyRegex.h in Headers */, 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | /* End PBXHeadersBuildPhase section */ 113 | 114 | /* Begin PBXNativeTarget section */ 115 | 0CEBDD231B39B8C3003A40BB /* PySwiftyRegex */ = { 116 | isa = PBXNativeTarget; 117 | buildConfigurationList = 0CEBDD351B39B8C4003A40BB /* Build configuration list for PBXNativeTarget "PySwiftyRegex" */; 118 | buildPhases = ( 119 | 0CEBDD1F1B39B8C3003A40BB /* Sources */, 120 | 0CEBDD201B39B8C3003A40BB /* Frameworks */, 121 | 0CEBDD211B39B8C3003A40BB /* Headers */, 122 | 0CEBDD221B39B8C3003A40BB /* Resources */, 123 | ); 124 | buildRules = ( 125 | ); 126 | dependencies = ( 127 | ); 128 | name = PySwiftyRegex; 129 | productName = PySwiftyRegex; 130 | productReference = 0CEBDD241B39B8C3003A40BB /* PySwiftyRegex.framework */; 131 | productType = "com.apple.product-type.framework"; 132 | }; 133 | 0CEBDD2C1B39B8C4003A40BB /* PySwiftyRegexTests */ = { 134 | isa = PBXNativeTarget; 135 | buildConfigurationList = 0CEBDD381B39B8C4003A40BB /* Build configuration list for PBXNativeTarget "PySwiftyRegexTests" */; 136 | buildPhases = ( 137 | 0CEBDD291B39B8C4003A40BB /* Sources */, 138 | 0CEBDD2A1B39B8C4003A40BB /* Frameworks */, 139 | 0CEBDD2B1B39B8C4003A40BB /* Resources */, 140 | ); 141 | buildRules = ( 142 | ); 143 | dependencies = ( 144 | 0CEBDD301B39B8C4003A40BB /* PBXTargetDependency */, 145 | ); 146 | name = PySwiftyRegexTests; 147 | productName = PySwiftyRegexTests; 148 | productReference = 0CEBDD2D1B39B8C4003A40BB /* PySwiftyRegexTests.xctest */; 149 | productType = "com.apple.product-type.bundle.unit-test"; 150 | }; 151 | /* End PBXNativeTarget section */ 152 | 153 | /* Begin PBXProject section */ 154 | 0CEBDCD51B39B2FB003A40BB /* Project object */ = { 155 | isa = PBXProject; 156 | attributes = { 157 | LastSwiftUpdateCheck = 0710; 158 | LastUpgradeCheck = 1030; 159 | ORGANIZATIONNAME = "Ce Zheng"; 160 | TargetAttributes = { 161 | 0CEBDD231B39B8C3003A40BB = { 162 | CreatedOnToolsVersion = 7.0; 163 | LastSwiftMigration = 1030; 164 | }; 165 | 0CEBDD2C1B39B8C4003A40BB = { 166 | CreatedOnToolsVersion = 7.0; 167 | LastSwiftMigration = 1030; 168 | }; 169 | }; 170 | }; 171 | buildConfigurationList = 0CEBDCD81B39B2FB003A40BB /* Build configuration list for PBXProject "PySwiftyRegex" */; 172 | compatibilityVersion = "Xcode 3.2"; 173 | developmentRegion = en; 174 | hasScannedForEncodings = 0; 175 | knownRegions = ( 176 | en, 177 | Base, 178 | ); 179 | mainGroup = 0CEBDCD41B39B2FB003A40BB; 180 | productRefGroup = 0CEBDCDF1B39B2FB003A40BB /* Products */; 181 | projectDirPath = ""; 182 | projectRoot = ""; 183 | targets = ( 184 | 0CEBDD231B39B8C3003A40BB /* PySwiftyRegex */, 185 | 0CEBDD2C1B39B8C4003A40BB /* PySwiftyRegexTests */, 186 | ); 187 | }; 188 | /* End PBXProject section */ 189 | 190 | /* Begin PBXResourcesBuildPhase section */ 191 | 0CEBDD221B39B8C3003A40BB /* Resources */ = { 192 | isa = PBXResourcesBuildPhase; 193 | buildActionMask = 2147483647; 194 | files = ( 195 | ); 196 | runOnlyForDeploymentPostprocessing = 0; 197 | }; 198 | 0CEBDD2B1B39B8C4003A40BB /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | ); 203 | runOnlyForDeploymentPostprocessing = 0; 204 | }; 205 | /* End PBXResourcesBuildPhase section */ 206 | 207 | /* Begin PBXSourcesBuildPhase section */ 208 | 0CEBDD1F1B39B8C3003A40BB /* Sources */ = { 209 | isa = PBXSourcesBuildPhase; 210 | buildActionMask = 2147483647; 211 | files = ( 212 | 0CEBDD3E1B39C5EC003A40BB /* PySwiftyRegex.swift in Sources */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | 0CEBDD291B39B8C4003A40BB /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 795691DB1C74A9B9002B1CA4 /* ReTests.swift in Sources */, 221 | 0CEBDD3C1B39C54B003A40BB /* ReRegexObjectTests.swift in Sources */, 222 | 0CEBDD3D1B39C54B003A40BB /* ReMatchObjectTests.swift in Sources */, 223 | 795691DE1C74AACB002B1CA4 /* TestHelpers.swift in Sources */, 224 | ); 225 | runOnlyForDeploymentPostprocessing = 0; 226 | }; 227 | /* End PBXSourcesBuildPhase section */ 228 | 229 | /* Begin PBXTargetDependency section */ 230 | 0CEBDD301B39B8C4003A40BB /* PBXTargetDependency */ = { 231 | isa = PBXTargetDependency; 232 | target = 0CEBDD231B39B8C3003A40BB /* PySwiftyRegex */; 233 | targetProxy = 0CEBDD2F1B39B8C4003A40BB /* PBXContainerItemProxy */; 234 | }; 235 | /* End PBXTargetDependency section */ 236 | 237 | /* Begin XCBuildConfiguration section */ 238 | 0CEBDCF01B39B2FC003A40BB /* Debug */ = { 239 | isa = XCBuildConfiguration; 240 | buildSettings = { 241 | ALWAYS_SEARCH_USER_PATHS = NO; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 243 | CLANG_CXX_LIBRARY = "libc++"; 244 | CLANG_ENABLE_MODULES = YES; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_COMMA = YES; 249 | CLANG_WARN_CONSTANT_CONVERSION = YES; 250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_EMPTY_BODY = YES; 253 | CLANG_WARN_ENUM_CONVERSION = YES; 254 | CLANG_WARN_INFINITE_RECURSION = YES; 255 | CLANG_WARN_INT_CONVERSION = YES; 256 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 257 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 258 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 260 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 261 | CLANG_WARN_STRICT_PROTOTYPES = YES; 262 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 263 | CLANG_WARN_UNREACHABLE_CODE = YES; 264 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 265 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 266 | COPY_PHASE_STRIP = NO; 267 | CURRENT_PROJECT_VERSION = 1; 268 | DEBUG_INFORMATION_FORMAT = dwarf; 269 | ENABLE_STRICT_OBJC_MSGSEND = YES; 270 | ENABLE_TESTABILITY = YES; 271 | GCC_C_LANGUAGE_STANDARD = gnu99; 272 | GCC_DYNAMIC_NO_PIC = NO; 273 | GCC_NO_COMMON_BLOCKS = YES; 274 | GCC_OPTIMIZATION_LEVEL = 0; 275 | GCC_PREPROCESSOR_DEFINITIONS = ( 276 | "DEBUG=1", 277 | "$(inherited)", 278 | ); 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | INFOPLIST_FILE = PySwiftyRegex/Info.plist; 286 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 287 | MTL_ENABLE_DEBUG_INFO = YES; 288 | ONLY_ACTIVE_ARCH = YES; 289 | PRODUCT_BUNDLE_IDENTIFIER = me.cezheng.PySwiftyRegex; 290 | PRODUCT_NAME = "$(PROJECT_NAME)"; 291 | SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos appletvsimulator iphonesimulator watchsimulator"; 292 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 293 | TARGETED_DEVICE_FAMILY = "1,2,3,4"; 294 | VERSIONING_SYSTEM = "apple-generic"; 295 | VERSION_INFO_PREFIX = ""; 296 | }; 297 | name = Debug; 298 | }; 299 | 0CEBDCF11B39B2FC003A40BB /* Release */ = { 300 | isa = XCBuildConfiguration; 301 | buildSettings = { 302 | ALWAYS_SEARCH_USER_PATHS = NO; 303 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 304 | CLANG_CXX_LIBRARY = "libc++"; 305 | CLANG_ENABLE_MODULES = YES; 306 | CLANG_ENABLE_OBJC_ARC = YES; 307 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 308 | CLANG_WARN_BOOL_CONVERSION = YES; 309 | CLANG_WARN_COMMA = YES; 310 | CLANG_WARN_CONSTANT_CONVERSION = YES; 311 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 312 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 313 | CLANG_WARN_EMPTY_BODY = YES; 314 | CLANG_WARN_ENUM_CONVERSION = YES; 315 | CLANG_WARN_INFINITE_RECURSION = YES; 316 | CLANG_WARN_INT_CONVERSION = YES; 317 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 318 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 319 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 322 | CLANG_WARN_STRICT_PROTOTYPES = YES; 323 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 324 | CLANG_WARN_UNREACHABLE_CODE = YES; 325 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 326 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 327 | COPY_PHASE_STRIP = NO; 328 | CURRENT_PROJECT_VERSION = 1; 329 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 330 | ENABLE_NS_ASSERTIONS = NO; 331 | ENABLE_STRICT_OBJC_MSGSEND = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu99; 333 | GCC_NO_COMMON_BLOCKS = YES; 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | INFOPLIST_FILE = PySwiftyRegex/Info.plist; 341 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 342 | MTL_ENABLE_DEBUG_INFO = NO; 343 | PRODUCT_BUNDLE_IDENTIFIER = me.cezheng.PySwiftyRegex; 344 | PRODUCT_NAME = "$(PROJECT_NAME)"; 345 | SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos appletvsimulator iphonesimulator watchsimulator"; 346 | TARGETED_DEVICE_FAMILY = "1,2,3,4"; 347 | VALIDATE_PRODUCT = YES; 348 | VERSIONING_SYSTEM = "apple-generic"; 349 | VERSION_INFO_PREFIX = ""; 350 | }; 351 | name = Release; 352 | }; 353 | 0CEBDD361B39B8C4003A40BB /* Debug */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | COMBINE_HIDPI_IMAGES = YES; 357 | DEFINES_MODULE = YES; 358 | DYLIB_COMPATIBILITY_VERSION = 1; 359 | DYLIB_CURRENT_VERSION = 1; 360 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 361 | FRAMEWORK_VERSION = A; 362 | GCC_GENERATE_TEST_COVERAGE_FILES = YES; 363 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 364 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 365 | MACH_O_TYPE = mh_dylib; 366 | MACOSX_DEPLOYMENT_TARGET = 10.9; 367 | SKIP_INSTALL = YES; 368 | SWIFT_VERSION = 5.0; 369 | }; 370 | name = Debug; 371 | }; 372 | 0CEBDD371B39B8C4003A40BB /* Release */ = { 373 | isa = XCBuildConfiguration; 374 | buildSettings = { 375 | COMBINE_HIDPI_IMAGES = YES; 376 | DEFINES_MODULE = YES; 377 | DYLIB_COMPATIBILITY_VERSION = 1; 378 | DYLIB_CURRENT_VERSION = 1; 379 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 380 | FRAMEWORK_VERSION = A; 381 | GCC_GENERATE_TEST_COVERAGE_FILES = YES; 382 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 383 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 384 | MACH_O_TYPE = mh_dylib; 385 | MACOSX_DEPLOYMENT_TARGET = 10.9; 386 | SKIP_INSTALL = YES; 387 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 388 | SWIFT_VERSION = 5.0; 389 | }; 390 | name = Release; 391 | }; 392 | 0CEBDD391B39B8C4003A40BB /* Debug */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | COMBINE_HIDPI_IMAGES = YES; 396 | INFOPLIST_FILE = PySwiftyRegexTests/Info.plist; 397 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 398 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 399 | MACOSX_DEPLOYMENT_TARGET = 10.9; 400 | PRODUCT_BUNDLE_IDENTIFIER = "me.cezheng.PySwiftyRegex-OSXTests"; 401 | PRODUCT_NAME = "$(TARGET_NAME)"; 402 | SDKROOT = macosx; 403 | SWIFT_VERSION = 5.0; 404 | }; 405 | name = Debug; 406 | }; 407 | 0CEBDD3A1B39B8C4003A40BB /* Release */ = { 408 | isa = XCBuildConfiguration; 409 | buildSettings = { 410 | COMBINE_HIDPI_IMAGES = YES; 411 | INFOPLIST_FILE = PySwiftyRegexTests/Info.plist; 412 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 413 | "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 414 | MACOSX_DEPLOYMENT_TARGET = 10.9; 415 | PRODUCT_BUNDLE_IDENTIFIER = "me.cezheng.PySwiftyRegex-OSXTests"; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | SDKROOT = macosx; 418 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 419 | SWIFT_VERSION = 5.0; 420 | }; 421 | name = Release; 422 | }; 423 | /* End XCBuildConfiguration section */ 424 | 425 | /* Begin XCConfigurationList section */ 426 | 0CEBDCD81B39B2FB003A40BB /* Build configuration list for PBXProject "PySwiftyRegex" */ = { 427 | isa = XCConfigurationList; 428 | buildConfigurations = ( 429 | 0CEBDCF01B39B2FC003A40BB /* Debug */, 430 | 0CEBDCF11B39B2FC003A40BB /* Release */, 431 | ); 432 | defaultConfigurationIsVisible = 0; 433 | defaultConfigurationName = Release; 434 | }; 435 | 0CEBDD351B39B8C4003A40BB /* Build configuration list for PBXNativeTarget "PySwiftyRegex" */ = { 436 | isa = XCConfigurationList; 437 | buildConfigurations = ( 438 | 0CEBDD361B39B8C4003A40BB /* Debug */, 439 | 0CEBDD371B39B8C4003A40BB /* Release */, 440 | ); 441 | defaultConfigurationIsVisible = 0; 442 | defaultConfigurationName = Release; 443 | }; 444 | 0CEBDD381B39B8C4003A40BB /* Build configuration list for PBXNativeTarget "PySwiftyRegexTests" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | 0CEBDD391B39B8C4003A40BB /* Debug */, 448 | 0CEBDD3A1B39B8C4003A40BB /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | defaultConfigurationName = Release; 452 | }; 453 | /* End XCConfigurationList section */ 454 | }; 455 | rootObject = 0CEBDCD51B39B2FB003A40BB /* Project object */; 456 | } 457 | -------------------------------------------------------------------------------- /PySwiftyRegex.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PySwiftyRegex.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PySwiftyRegex.xcodeproj/xcshareddata/xcschemes/PySwiftyRegex.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /PySwiftyRegex/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2015ー2016 Ce Zheng. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /PySwiftyRegex/PySwiftyRegex.h: -------------------------------------------------------------------------------- 1 | // PySwiftyRegex.h 2 | // Copyright (c) 2015ー2016 Ce Zheng 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | //! Project version number for PySwiftyRegex. 25 | FOUNDATION_EXPORT double PySwiftyRegexVersionNumber; 26 | 27 | //! Project version string for PySwiftyRegex. 28 | FOUNDATION_EXPORT const unsigned char PySwiftyRegexVersionString[]; 29 | 30 | // In this header, you should import all the public headers of your framework using statements like #import 31 | 32 | 33 | -------------------------------------------------------------------------------- /PySwiftyRegex/PySwiftyRegex.swift: -------------------------------------------------------------------------------- 1 | // PySwiftyRegex.swift 2 | // Copyright (c) 2015ー2016 Ce Zheng 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | import Foundation 23 | 24 | /** 25 | * Counterpart of Python's re module, but as a class. 26 | */ 27 | public class re { 28 | // MARK: - re methods 29 | /** 30 | Compile a regular expression pattern into a RegexObject object, which can be used for matching using its match() and search() methods, described below. 31 | 32 | See https://docs.python.org/2/library/re.html#re.compile 33 | 34 | - parameter pattern: regular expression pattern string 35 | - parameter flags: NSRegularExpressionOptions value 36 | 37 | - returns: The created RegexObject object. If the pattern is invalid, RegexObject.isValid is false, and all methods have a default return value. 38 | */ 39 | public static func compile(_ pattern: String, flags: RegexObject.Flag = []) -> RegexObject { 40 | return RegexObject(pattern: pattern, flags: flags) 41 | } 42 | 43 | /** 44 | Scan through string looking for the first location where the regular expression pattern produces a match, and return a corresponding MatchObject instance. 45 | 46 | See https://docs.python.org/2/library/re.html#re.search 47 | 48 | - parameter pattern: regular expression pattern string 49 | - parameter string: string to be searched 50 | - parameter flags: NSRegularExpressionOptions value 51 | 52 | - returns: Corresponding MatchObject instance. Return nil if no position in the string matches the pattern or pattern is invalid; note that this is different from finding a zero-length match at some point in the string. 53 | */ 54 | public static func search(_ pattern: String, _ string: String, flags: RegexObject.Flag = []) -> MatchObject? { 55 | return re.compile(pattern, flags: flags).search(string) 56 | } 57 | 58 | /** 59 | If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding MatchObject instance. 60 | 61 | See https://docs.python.org/2/library/re.html#re.match 62 | 63 | - parameter pattern: regular expression pattern string 64 | - parameter string: string to be searched 65 | - parameter flags: NSRegularExpressionOptions value 66 | 67 | - returns: Corresponding MatchObject instance. Return nil if the string does not match the pattern or pattern is invalid; note that this is different from a zero-length match. 68 | */ 69 | public static func match(_ pattern: String, _ string: String, flags: RegexObject.Flag = []) -> MatchObject? { 70 | return re.compile(pattern, flags: flags).match(string) 71 | } 72 | 73 | /** 74 | Split string by the occurrences of pattern. If capturing parentheses are used in pattern, then the text of all groups in the pattern are also returned as part of the resulting list. If maxsplit is nonzero, at most maxsplit splits occur, and the remainder of the string is returned as the final element of the list. 75 | 76 | See https://docs.python.org/2/library/re.html#re.split 77 | 78 | - parameter pattern: regular expression pattern string 79 | - parameter string: string to be splitted 80 | - parameter maxsplit: maximum number of times to split the string, defaults to 0, meaning no limit is applied 81 | - parameter flags: NSRegularExpressionOptions value 82 | 83 | - returns: Array of splitted strings 84 | */ 85 | public static func split(_ pattern: String, _ string: String, _ maxsplit: Int = 0, flags: RegexObject.Flag = []) -> [String?] { 86 | return re.compile(pattern, flags: flags).split(string, maxsplit) 87 | } 88 | 89 | /** 90 | Return all non-overlapping matches of pattern in string, as a list of strings. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result unless they touch the beginning of another match. 91 | 92 | See https://docs.python.org/2/library/re.html#re.findall 93 | 94 | - parameter pattern: regular expression pattern string 95 | - parameter string: string to be searched 96 | - parameter flags: NSRegularExpressionOptions value 97 | 98 | - returns: Array of matched substrings 99 | */ 100 | public static func findall(_ pattern: String, _ string: String, flags: RegexObject.Flag = []) -> [String] { 101 | return re.compile(pattern, flags: flags).findall(string) 102 | } 103 | 104 | /** 105 | Return an array of MatchObject instances over all non-overlapping matches for the RE pattern in string. The string is scanned left-to-right, and matches are returned in the order found. Empty matches are included in the result unless they touch the beginning of another match. 106 | 107 | See https://docs.python.org/2/library/re.html#re.finditer 108 | 109 | - parameter pattern: regular expression pattern string 110 | - parameter string: string to be searched 111 | - parameter flags: NSRegularExpressionOptions value 112 | 113 | - returns: Array of match results as MatchObject instances 114 | */ 115 | public static func finditer(_ pattern: String, _ string: String, flags: RegexObject.Flag = []) -> [MatchObject] { 116 | return re.compile(pattern, flags: flags).finditer(string) 117 | } 118 | 119 | /** 120 | Return the string obtained by replacing the leftmost non-overlapping occurrences of pattern in string by the replacement repl. If the pattern isn’t found, string is returned unchanged. Different from python, passing a repl as a closure is not supported. 121 | 122 | See https://docs.python.org/2/library/re.html#re.sub 123 | 124 | - parameter pattern: regular expression pattern string 125 | - parameter repl: replacement string 126 | - parameter string: string to be searched and replaced 127 | - parameter count: maximum number of times to perform replace operations to the string 128 | - parameter flags: NSRegularExpressionOptions value 129 | 130 | - returns: replaced string 131 | */ 132 | public static func sub(_ pattern: String, _ repl: String, _ string: String, _ count: Int = 0, flags: RegexObject.Flag = []) -> String { 133 | return re.compile(pattern, flags: flags).sub(repl, string, count) 134 | } 135 | 136 | /** 137 | Perform the same operation as sub(), but return a tuple (new_string, number_of_subs_made) as (String, Int) 138 | 139 | See https://docs.python.org/2/library/re.html#re.subn 140 | 141 | - parameter pattern: regular expression pattern string 142 | - parameter repl: replacement string 143 | - parameter string: string to be searched and replaced 144 | - parameter count: maximum number of times to perform replace operations to the string 145 | - parameter flags: NSRegularExpressionOptions value 146 | 147 | - returns: a tuple (new_string, number_of_subs_made) as (String, Int) 148 | */ 149 | public static func subn(_ pattern: String, _ repl: String, _ string: String, _ count: Int = 0, flags: RegexObject.Flag = []) -> (String, Int) { 150 | return re.compile(pattern, flags: flags).subn(repl, string, count) 151 | } 152 | 153 | // MARK: - RegexObject 154 | /** 155 | * Counterpart of Python's re.RegexObject 156 | */ 157 | public class RegexObject { 158 | /// Typealias for NSRegularExpressionOptions 159 | public typealias Flag = NSRegularExpression.Options 160 | 161 | /// Whether this object is valid or not 162 | public var isValid: Bool { 163 | return regex != nil 164 | } 165 | 166 | /// Pattern used to construct this RegexObject 167 | public let pattern: String 168 | 169 | private let regex: NSRegularExpression? 170 | 171 | /// Underlying NSRegularExpression Object 172 | public var nsRegex: NSRegularExpression? { 173 | return regex 174 | } 175 | 176 | /// NSRegularExpressionOptions used to contructor this RegexObject 177 | public var flags: Flag { 178 | return regex?.options ?? [] 179 | } 180 | 181 | /// Number of capturing groups 182 | public var groups: Int { 183 | return regex?.numberOfCaptureGroups ?? 0 184 | } 185 | 186 | /** 187 | Create A re.RegexObject Instance 188 | 189 | - parameter pattern: regular expression pattern string 190 | - parameter flags: NSRegularExpressionOptions value 191 | 192 | - returns: The created RegexObject object. If the pattern is invalid, RegexObject.isValid is false, and all methods have a default return value. 193 | */ 194 | public required init(pattern: String, flags: Flag = []) { 195 | self.pattern = pattern 196 | do { 197 | self.regex = try NSRegularExpression(pattern: pattern, options: flags) 198 | } catch let error as NSError { 199 | self.regex = nil 200 | debugPrint(error) 201 | } 202 | } 203 | 204 | /** 205 | Scan through string looking for a location where this regular expression produces a match, and return a corresponding MatchObject instance. Return nil if no position in the string matches the pattern; note that this is different from finding a zero-length match at some point in the string. 206 | 207 | See https://docs.python.org/2/library/re.html#re.RegexObject.search 208 | 209 | - parameter string: string to be searched 210 | - parameter pos: position in string where the search is to start, defaults to 0 211 | - parameter endpos: position in string where the search it to end (non-inclusive), defaults to nil, meaning the end of the string. If endpos is less than pos, no match will be found. 212 | - parameter options: NSMatchOptions value 213 | 214 | - returns: search result as MatchObject instance if a match is found, otherwise return nil 215 | */ 216 | public func search(_ string: String, _ pos: Int = 0, _ endpos: Int? = nil, options: NSRegularExpression.MatchingOptions = []) -> MatchObject? { 217 | guard let regex = regex else { 218 | return nil 219 | } 220 | let start = pos > 0 ?pos :0 221 | let end = endpos ?? string.utf16.count 222 | let length = max(0, end - start) 223 | let range = NSRange(location: start, length: length) 224 | if let match = regex.firstMatch(in: string, options: options, range: range) { 225 | return MatchObject(string: string, match: match) 226 | } 227 | return nil 228 | } 229 | 230 | /** 231 | If zero or more characters at the beginning of string match this regular expression, return a corresponding MatchObject instance. Return nil if the string does not match the pattern; note that this is different from a zero-length match. 232 | 233 | See https://docs.python.org/2/library/re.html#re.RegexObject.match 234 | 235 | - parameter string: string to be matched 236 | - parameter pos: position in string where the search is to start, defaults to 0 237 | - parameter endpos: position in string where the search it to end (non-inclusive), defaults to nil, meaning the end of the string. If endpos is less than pos, no match will be found. 238 | 239 | - returns: match result as MatchObject instance if a match is found, otherwise return nil 240 | */ 241 | public func match(_ string: String, _ pos: Int = 0, _ endpos: Int? = nil) -> MatchObject? { 242 | return search(string, pos, endpos, options: [.anchored]) 243 | } 244 | 245 | /** 246 | Identical to the re.split() function, using the compiled pattern. 247 | 248 | See https://docs.python.org/2/library/re.html#re.RegexObject.split 249 | 250 | - parameter string: string to be splitted 251 | - parameter maxsplit: maximum number of times to split the string, defaults to 0, meaning no limit is applied 252 | 253 | - returns: Array of splitted strings 254 | */ 255 | public func split(_ string: String, _ maxsplit: Int = 0) -> [String?] { 256 | guard let regex = regex else { 257 | return [] 258 | } 259 | var splitsLeft = maxsplit == 0 ? Int.max : (maxsplit < 0 ? 0 : maxsplit) 260 | let range = NSRange(location: 0, length: string.utf16.count) 261 | var results = [String?]() 262 | var start = string.startIndex 263 | var end = string.startIndex 264 | regex.enumerateMatches(in: string, options: [], range: range) { result, _, stop in 265 | if splitsLeft <= 0 { 266 | stop.pointee = true 267 | return 268 | } 269 | 270 | guard let result = result, result.range.length > 0 else { 271 | return 272 | } 273 | 274 | end = string.index(string.startIndex, offsetBy: result.range.location) 275 | results.append(String(string[start.. 0 { 277 | results += MatchObject(string: string, match: result).groups() 278 | } 279 | splitsLeft -= 1 280 | start = string.index(end, offsetBy: result.range.length) 281 | } 282 | if start <= string.endIndex { 283 | results.append(String(string[start.. [String] { 300 | return finditer(string, pos, endpos).map { $0.group()! } 301 | } 302 | 303 | /** 304 | Similar to the re.finditer() function, using the compiled pattern, but also accepts optional pos and endpos parameters that limit the search region like for match(). 305 | 306 | https://docs.python.org/2/library/re.html#re.RegexObject.finditer 307 | 308 | - parameter string: string to be matched 309 | - parameter pos: position in string where the search is to start, defaults to 0 310 | - parameter endpos: position in string where the search it to end (non-inclusive), defaults to nil, meaning the end of the string. If endpos is less than pos, no match will be found. 311 | 312 | - returns: Array of match results as MatchObject instances 313 | */ 314 | public func finditer(_ string: String, _ pos: Int = 0, _ endpos: Int? = nil) -> [MatchObject] { 315 | guard let regex = regex else { 316 | return [] 317 | } 318 | let start = pos > 0 ?pos :0 319 | let end = endpos ?? string.utf16.count 320 | let length = max(0, end - start) 321 | let range = NSRange(location: start, length: length) 322 | return regex.matches(in: string, options: [], range: range).map { MatchObject(string: string, match: $0) } 323 | } 324 | 325 | /** 326 | Identical to the re.sub() function, using the compiled pattern. 327 | 328 | See https://docs.python.org/2/library/re.html#re.RegexObject.sub 329 | 330 | - parameter repl: replacement string 331 | - parameter string: string to be searched and replaced 332 | - parameter count: maximum number of times to perform replace operations to the string 333 | 334 | - returns: replaced string 335 | */ 336 | public func sub(_ repl: String, _ string: String, _ count: Int = 0) -> String { 337 | return subn(repl, string, count).0 338 | } 339 | 340 | /** 341 | Identical to the re.subn() function, using the compiled pattern. 342 | 343 | See https://docs.python.org/2/library/re.html#re.RegexObject.subn 344 | 345 | - parameter repl: replacement string 346 | - parameter string: string to be searched and replaced 347 | - parameter count: maximum number of times to perform replace operations to the string 348 | 349 | - returns: a tuple (new_string, number_of_subs_made) as (String, Int) 350 | */ 351 | public func subn(_ repl: String, _ string: String, _ count: Int = 0) -> (String, Int) { 352 | guard let regex = regex else { 353 | return (string, 0) 354 | } 355 | let range = NSRange(location: 0, length: string.utf16.count) 356 | let mutable = NSMutableString(string: string) 357 | let maxCount = count == 0 ? Int.max : (count > 0 ? count : 0) 358 | var n = 0 359 | var offset = 0 360 | regex.enumerateMatches(in: string, options: [], range: range) { result, _, stop in 361 | if maxCount <= n { 362 | stop.pointee = true 363 | return 364 | } 365 | if let result = result { 366 | n += 1 367 | let resultRange = NSRange(location: result.range.location + offset, length: result.range.length) 368 | let lengthBeforeReplace = mutable.length 369 | regex.replaceMatches(in: mutable, options: [], range: resultRange, withTemplate: repl) 370 | offset += mutable.length - lengthBeforeReplace 371 | } 372 | } 373 | return (mutable as String, n) 374 | } 375 | } 376 | 377 | // MARK: - MatchObject 378 | /** 379 | * Counterpart of Python's re.MatchObject 380 | */ 381 | public final class MatchObject { 382 | /// String matched 383 | public let string: String 384 | 385 | /// Underlying NSTextCheckingResult 386 | public let match: NSTextCheckingResult 387 | 388 | init(string: String, match: NSTextCheckingResult) { 389 | self.string = string 390 | self.match = match 391 | } 392 | 393 | /** 394 | Return the string obtained by doing backslash substitution on the template string template, as done by the sub() method. 395 | 396 | Note that named backreferences in python is not supported here since NSRegularExpression does not have this feature. 397 | 398 | See https://docs.python.org/2/library/re.html#re.MatchObject.expand 399 | 400 | - parameter template: regular expression template decribing the expanded format 401 | 402 | - returns: expanded string 403 | */ 404 | public func expand(_ template: String) -> String { 405 | guard let regex = match.regularExpression else { 406 | return "" 407 | } 408 | return regex.replacementString(for: match, in: string, offset: 0, template: template) 409 | } 410 | 411 | /** 412 | Returns one subgroup of the match. If the group number is negative or larger than the number of groups defined in the pattern, nil returned. If a group is contained in a part of the pattern that did not match, the corresponding result is nil. If a group is contained in a part of the pattern that matched multiple times, the last match is returned. 413 | 414 | Note that different from python's group function this function does not accept multiple arguments due to ambiguous syntax. If you would like to use multiple arguments pass in an array instead. 415 | 416 | See https://docs.python.org/2/library/re.html#re.MatchObject.group 417 | 418 | - parameter index: group index, defaults to 0, meaning the entire matching string 419 | 420 | - returns: string of the matching group 421 | */ 422 | public func group(_ index: Int = 0) -> String? { 423 | guard let range = span(index), range.lowerBound < string.endIndex else { 424 | return nil 425 | } 426 | return String(string[range]) 427 | } 428 | 429 | /** 430 | Returns one or more subgroups of the match. If a group number is negative or larger than the number of groups defined in the pattern, nil is inserted at the relevant index of the returned array. If a group is contained in a part of the pattern that did not match, the corresponding result is None. If a group is contained in a part of the pattern that matched multiple times, the last match is returned. 431 | 432 | See https://docs.python.org/2/library/re.html#re.MatchObject.group 433 | 434 | - parameter indexes: array of group indexes to get 435 | 436 | - returns: array of strings of the matching groups 437 | */ 438 | public func group(_ indexes: [Int]) -> [String?] { 439 | return indexes.map { group($0) } 440 | } 441 | 442 | /** 443 | Return an array containing all the subgroups of the match, from 1 up to however many groups are in the pattern. The default argument is used for groups that did not participate in the match. 444 | 445 | Note that python version of this function returns a tuple while this one returns an array due to the fact that swift cannot specify a variadic tuple as return value. 446 | 447 | See https://docs.python.org/2/library/re.html#re.MatchObject.groups 448 | 449 | - parameter defaultValue: default value string 450 | 451 | - returns: array of all matching subgroups as String 452 | */ 453 | public func groups(_ defaultValue: String) -> [String] { 454 | return (1.. [String?] { 467 | return (1.. Range? { 480 | if index >= match.numberOfRanges { 481 | return nil 482 | } 483 | let nsrange = match.range(at: index) 484 | 485 | if nsrange.location == NSNotFound { 486 | return string.endIndex.. 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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /PySwiftyRegexTests/ReMatchObjectTests.swift: -------------------------------------------------------------------------------- 1 | // ReMatchObjectTests.swift 2 | // Copyright (c) 2015ー2016 Ce Zheng 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | import XCTest 23 | import PySwiftyRegex 24 | 25 | class ReMatchObjectTests: XCTestCase { 26 | func testExpand() { 27 | let regex = re.compile("(this).+(that)") 28 | let string = "this one is different from that one." 29 | let m = regex.match(string) 30 | XCTAssertNotNil(m) 31 | let match = m! 32 | XCTAssertEqual(match.string, string) 33 | XCTAssertEqual(match.expand("$2 ~ $1"), "that ~ this") 34 | } 35 | 36 | func testGroups() { 37 | let m = re.match("(\\d+)\\.(\\d+)", "24.1632") 38 | XCTAssertNotNil(m) 39 | let match = m! 40 | XCTAssertEqual(match.string, "24.1632") 41 | let groups = match.groups() 42 | XCTAssertFalse(groups.isEmpty) 43 | XCTAssertEqual(groups[0]!, "24") 44 | XCTAssertEqual(groups[1]!, "1632") 45 | } 46 | 47 | func testGroupsWithNoGroup() { 48 | let m = re.match("\\d+\\.\\d+", "24.1632") 49 | XCTAssertNotNil(m) 50 | let match = m! 51 | XCTAssertEqual(match.string, "24.1632") 52 | let groups = match.groups() 53 | XCTAssertTrue(groups.isEmpty) 54 | } 55 | 56 | func testGroupsWithDefault() { 57 | let m = re.match("(\\d+)\\.?(\\d+)?", "24") 58 | XCTAssertNotNil(m) 59 | let match = m! 60 | let groups = match.groups() 61 | XCTAssertEqual(groups[0]!, "24") 62 | XCTAssertNil(groups[1]) 63 | XCTAssertEqual(match.groups("0"), ["24", "0"]) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /PySwiftyRegexTests/ReRegexObjectTests.swift: -------------------------------------------------------------------------------- 1 | // ReRegexObjectTests.swift 2 | // Copyright (c) 2015ー2016 Ce Zheng 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | import XCTest 23 | import PySwiftyRegex 24 | 25 | class ReRegexObjectTests: XCTestCase { 26 | func testMatchSuccess() { 27 | let regex = re.compile("(this).+(that)") 28 | let string = "this one is different from that one." 29 | let m = regex.match(string) 30 | XCTAssertNotNil(m) 31 | let match = m! 32 | XCTAssertEqual(match.string, string) 33 | XCTAssertEqual(match.group()!, "this one is different from that") 34 | XCTAssertEqual(match.group(1)!, "this") 35 | XCTAssertEqual(match.group(2)!, "that") 36 | XCTAssertEqual(match.span()!, string.startIndex.. (_ left: (T1, T2), _ right: (T1, T2)) { 25 | XCTAssertTrue((left.0 == right.0) && (left.1 == right.1)) 26 | } 27 | 28 | func AssertEqual(_ left: [T?], _ right: [T?]) { 29 | XCTAssertEqual(left.count, right.count) 30 | for (index, item) in left.enumerated() { 31 | XCTAssertEqual(item, right[index]) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README-ja.md: -------------------------------------------------------------------------------- 1 | # PySwiftyRegex 2 | [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/PySwiftyRegex.svg)](https://cocoapods.org/pods/PySwiftyRegex) 3 | [![License](https://img.shields.io/cocoapods/l/PySwiftyRegex.svg?style=flat&color=gray)](http://opensource.org/licenses/MIT) 4 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Platform](https://img.shields.io/cocoapods/p/PySwiftyRegex.svg?style=flat)](http://cocoadocs.org/docsets/PySwiftyRegex) 6 | [![Twitter](https://img.shields.io/badge/twitter-@AdamoCheng-blue.svg?style=flat)](http://twitter.com/AdamoCheng) 7 | 8 | Pythonのようなスッキリした正規表現ライブラリー。 9 | 10 | [English](README.md) 11 | [简体中文](README-zh.md) 12 | [한국어](README-ko.md) 13 | 14 | ## コードをみましょう 15 | 16 | ```swift 17 | import PySwiftyRegex 18 | 19 | if let m = re.search("[Tt]his is (.*?)easy", "I think this is really easy!!!") { 20 | m.group() // "this is really easy" 21 | m.group(1) // "really " 22 | } 23 | ``` 24 | よく使われるメッソドの用例は[こちら](#more_usage)。 25 | 26 | ## 環境 27 | 28 | - iOS 7.0+ / Mac OS X 10.9+ 29 | - Xcode 8.0+ 30 | 31 | > Swift 2.3はバージョン[0.3.0](../../releases/tag/0.3.0)をご利用ください。 32 | 33 | ## インストール 34 | > **Embedded frameworks を使うには iOS 8 または OS X Mavericks 以上は必要です** 35 | > 36 | > Deployment Target は iOS 7 のプロジェクトで `PySwiftyRegex` を使うには, [PySwiftyRegex.swift](PySwiftyRegex/PySwiftyRegex.swift) のソースファイルをダウンロードして、Xcodeプロジェクトに追加するのは必要となります。 37 | 38 | ### CocoaPods(iOS 8+, OS X 10.9+) 39 | [Cocoapods](http://cocoapods.org/) で簡単に `PySwiftyRegex` をインストールできます。 下記のように`Podfile`を編集してください: 40 | 41 | ```ruby 42 | platform :ios, '8.0' 43 | use_frameworks! 44 | 45 | target 'MyApp' do 46 | pod 'PySwiftyRegex', '~> 1.0.0' 47 | end 48 | ``` 49 | 50 | そして、下記のコマンドを実行してください: 51 | 52 | ```bash 53 | $ pod install 54 | ``` 55 | 56 | ### Carthage(iOS 8+, OS X 10.9+) 57 | 下記の行を `Cartfile` か `Cartfile.private` かに追加してください: 58 | 59 | ``` 60 | github "cezheng/PySwiftyRegex" ~> 1.0.0 61 | ``` 62 | そして、下記のコマンドを実行してください: 63 | 64 | ``` 65 | $ carthage update 66 | ``` 67 | 最後に、ビルドターゲットの`General` -> `Embedded Binaries`に、Carthageがビルドした`PySwiftyRegex.framework`を追加してください。 68 | 69 | ## 対応したreメソッド 70 | [**re**](https://docs.python.org/2/library/re.html) モデルを使ったことがあれば, すぐこのライブラリーをご利用できると思います。もしなかったら、下記のPythonドキュメントのリンクをご覧いただけると、このシンプルなモデルに一目惚れするかもしれませんw 71 | ### [re](https://docs.python.org/2/library/re.html#module-contents) 72 | * [re.compile](https://docs.python.org/2/library/re.html#re.compile) 73 | * [re.search](https://docs.python.org/2/library/re.html#re.search) 74 | * [re.match](https://docs.python.org/2/library/re.html#re.match) 75 | * [re.split](https://docs.python.org/2/library/re.html#re.split) 76 | * [re.findall](https://docs.python.org/2/library/re.html#re.findall) 77 | * [re.finditer](https://docs.python.org/2/library/re.html#re.finditer) 78 | * [re.sub](https://docs.python.org/2/library/re.html#re.sub) 79 | * [re.subn](https://docs.python.org/2/library/re.html#re.subn) 80 | 81 | ### [re.RegexObject](https://docs.python.org/2/library/re.html#regular-expression-objects) 82 | * [search](https://docs.python.org/2/library/re.html#re.RegexObject.search) 83 | * [match](https://docs.python.org/2/library/re.html#re.RegexObject.match) 84 | * [split](https://docs.python.org/2/library/re.html#re.RegexObject.split) 85 | * [findall](https://docs.python.org/2/library/re.html#re.RegexObject.findall) 86 | * [finditer](https://docs.python.org/2/library/re.html#re.RegexObject.finditer) 87 | * [sub](https://docs.python.org/2/library/re.html#re.RegexObject.sub) 88 | * [subn](https://docs.python.org/2/library/re.html#re.RegexObject.subn) 89 | 90 | ### [re.MatchObject](https://docs.python.org/2/library/re.html#match-objects) 91 | * [expand](https://docs.python.org/2/library/re.html#re.MatchObject.expand) 92 | * [group](https://docs.python.org/2/library/re.html#re.MatchObject.group) 93 | * [groups](https://docs.python.org/2/library/re.html#re.MatchObject.groups) 94 | * [span](https://docs.python.org/2/library/re.html#re.MatchObject.span) 95 | 96 | ## よく使われるメッソドの用例 97 | ### RegexObjectをコンパイルする 98 | ```swift 99 | let regex = re.compile("this(.+)that") 100 | ``` 101 | ### 文字列の始めからマッチングする 102 | ```swift 103 | if let m = regex.match("this one is different from that") { 104 | m.group() //"this one is different from that" 105 | m.group(1) //" one is different from " 106 | } 107 | ``` 108 | ### 文字列の中にパターンを探す (first match) 109 | ```swift 110 | if let m = regex.search("I want this one, not that one") { 111 | m.group() //"this one, not that one" 112 | m.group(1) //" one, not " 113 | } 114 | ``` 115 | ### マッチングできた全ての文字列を取得する 116 | ```swift 117 | regex.findall("this or that, this and that") // ["this or that", "this and that"] 118 | ``` 119 | ### マッチングできた全てのMatchObjectを取得する 120 | ```swift 121 | for m in regex.finditer("this or that, this and that") { 122 | m.group() // 1st time: "this or that", second time: "this and that" 123 | m.group(1) // 1st time: " or ", second time: " and " 124 | } 125 | ``` 126 | ### パターンで文字列を分割する 127 | ```swift 128 | let regex = re.compile("[\\+\\-\\*/]") 129 | 130 | // デフォルト、全て分割する 131 | regex.split("1+2-3*4/5") // ["1", "2", "3", "4", "5"] 132 | 133 | // 最大分割回数 = 2 134 | regex.split("1+2-3*4/5", 2) // ["1", "2", "3*4/5"] 135 | ``` 136 | ### パターンで文字列を置換する 137 | ```swift 138 | let regex = re.compile("[Yy]ou") 139 | 140 | // 全て置換する (この例は2回) 141 | regex.sub("u", "You guys go grap your food") // "u guys go grap ur food" 142 | regex.subn("u", "You guys go grap your food") // ("u guys go grap ur food", 2) 143 | 144 | // 最大置換回数を1回にする (この例は1回) 145 | regex.sub("u", "You guys go grap your food", 1) // "u guys go grap your food" 146 | regex.subn("u", "You guys go grap your food", 1) // ("u guys go grap your food", 1) 147 | ``` 148 | 149 | ## ライセンス 150 | 151 | `PySwiftyRegex` のオープンソースライセンスは MIT です。 詳しくはこちら [LICENSE](LICENSE) 。 152 | -------------------------------------------------------------------------------- /README-ko.md: -------------------------------------------------------------------------------- 1 | # PySwiftyRegex 2 | [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/PySwiftyRegex.svg)](https://cocoapods.org/pods/PySwiftyRegex) 3 | [![License](https://img.shields.io/cocoapods/l/PySwiftyRegex.svg?style=flat&color=gray)](http://opensource.org/licenses/MIT) 4 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Platform](https://img.shields.io/cocoapods/p/PySwiftyRegex.svg?style=flat)](http://cocoadocs.org/docsets/PySwiftyRegex) 6 | [![Twitter](https://img.shields.io/badge/twitter-@AdamoCheng-blue.svg?style=flat)](http://twitter.com/AdamoCheng) 7 | 8 | Swift에서 정규표현식을 Python처럼 쉽게 다뤄보세요. 9 | 10 | [English](README.md) 11 | [简体中文](README-zh.md) 12 | [日本語](README-ja.md) 13 | 14 | ## 굉장히 쉽습니다 15 | 16 | ```swift 17 | import PySwiftyRegex 18 | 19 | if let m = re.search("[Tt]his is (.*?)easy", "I think this is really easy!!!") { 20 | m.group() // "this is really easy" 21 | m.group(1) // "really " 22 | } 23 | ``` 24 | 25 | 아래에서 [더 많은 예제](#more_usage)를 볼 수 있습니다. 26 | 27 | ## 요구사항 28 | 29 | - iOS 7.0+ / Mac OS X 10.9+ 30 | - Xcode 8.0+ 31 | 32 | > Swift 2.3의 경우 버전 [0.3.0](../../releases/tag/0.3.0)를 이용해주십시오. 33 | 34 | ## 설치하기 35 | > **임베드된 프레임워크를 사용하려면 iOS 8 또는 OS X Mavericks 이상을 지원해야 합니다.** 36 | > 37 | > `PySwiftyRegex`을 iOS 7 타겟 프로젝트에서 사용하려면 [CocoaSeeds](#cocoaseeds-for-ios7)를 사용하거나 혹은 [PySwiftyRegex.swift](PySwiftyRegex/PySwiftyRegex.swift) 파일을 다운받아 프로젝트에 직접 포함시켜야 합니다. 38 | 39 | ### CocoaPods (iOS 8+, OS X 10.9+) 40 | 41 | [CocoaPods](http://cocoapods.org/)를 사용해서 `PySwiftyRegex`를 쉽게 설치할 수 있습니다. 다음과 같은 내용의 **Podfile**을 만들어주세요. 42 | 43 | ```ruby 44 | platform :ios, '8.0' 45 | use_frameworks! 46 | 47 | target 'MyApp' do 48 | pod 'PySwiftyRegex', '~> 1.0.0' 49 | end 50 | ``` 51 | 52 | 그리고 쉘에서 아래 명령어를 실행하면 설치됩니다. 53 | 54 | ```bash 55 | $ pod install 56 | ``` 57 | 58 | ### Carthage (iOS 8+, OS X 10.9+) 59 | 60 | **Cartfile** 또는 **Cartfile.private**에 아래 라인을 추가합니다. 61 | 62 | ``` 63 | github "cezheng/PySwiftyRegex" ~> 1.0.0 64 | ``` 65 | 66 | 그리고 쉘에서 다음 명령어를 실행합니다. 67 | 68 | ``` 69 | $ carthage update 70 | ``` 71 | 72 | Carthage가 생성한 **PySwiftyRegex.framework**를 Xcode 프로젝트의 'General' 설정 아래의 'Embedded Binaries'에 추가합니다. 73 | 74 | ### CocoaSeeds (iOS 7+) 75 | 76 | [CocoaSeeds](https://github.com/devxoul/CocoaSeeds)를 사용하면 Swift로 작성된 라이브러리를 iOS 7 프로젝트에서 사용할 수 있습니다. 77 | 78 | 먼저, **Seedfile**을 생성합니다. 79 | 80 | ```ruby 81 | target :MyApp do 82 | github 'cezheng/PySwiftyRegex', '1.0.0', :files => 'PySwiftyRegex/PySwiftyRegex.swift' 83 | end 84 | ``` 85 | 86 | 그리고 다음과 같은 쉘 명령어를 실행합니다. 87 | 88 | ```console 89 | $ seed install 90 | ``` 91 | 92 | PySwiftyRegex.swift 파일이 Xcode 프로젝트에 자동으로 포함된 것을 볼 수 있습니다. 즐코딩! 93 | 94 | ## 사용 가능한 re 모듈 95 | 96 | Python의 [**re**](https://docs.python.org/2/library/re.html) 모듈에 익숙하다면 사용하는데 어려움이 없을 것입니다. 처음이거나 익숙하지 않은 경우, 아래 항목들을 보고 Python에서 정규표현식을 다루는 방식이 `NSRegularExpression`보다 어떻게 더 좋은지 확인해보세요. 97 | 98 | ### [re](https://docs.python.org/2/library/re.html#module-contents) 99 | * [re.compile](https://docs.python.org/2/library/re.html#re.compile) 100 | * [re.search](https://docs.python.org/2/library/re.html#re.search) 101 | * [re.match](https://docs.python.org/2/library/re.html#re.match) 102 | * [re.split](https://docs.python.org/2/library/re.html#re.split) 103 | * [re.findall](https://docs.python.org/2/library/re.html#re.findall) 104 | * [re.finditer](https://docs.python.org/2/library/re.html#re.finditer) 105 | * [re.sub](https://docs.python.org/2/library/re.html#re.sub) 106 | * [re.subn](https://docs.python.org/2/library/re.html#re.subn) 107 | 108 | ### [re.RegexObject](https://docs.python.org/2/library/re.html#regular-expression-objects) 109 | * [search](https://docs.python.org/2/library/re.html#re.RegexObject.search) 110 | * [match](https://docs.python.org/2/library/re.html#re.RegexObject.match) 111 | * [split](https://docs.python.org/2/library/re.html#re.RegexObject.split) 112 | * [findall](https://docs.python.org/2/library/re.html#re.RegexObject.findall) 113 | * [finditer](https://docs.python.org/2/library/re.html#re.RegexObject.finditer) 114 | * [sub](https://docs.python.org/2/library/re.html#re.RegexObject.sub) 115 | * [subn](https://docs.python.org/2/library/re.html#re.RegexObject.subn) 116 | 117 | ### [re.MatchObject](https://docs.python.org/2/library/re.html#match-objects) 118 | * [expand](https://docs.python.org/2/library/re.html#re.MatchObject.expand) 119 | * [group](https://docs.python.org/2/library/re.html#re.MatchObject.group) 120 | * [groups](https://docs.python.org/2/library/re.html#re.MatchObject.groups) 121 | * [span](https://docs.python.org/2/library/re.html#re.MatchObject.span) 122 | 123 | ## 더 많은 예제 124 | ### 재사용을 위해 RegexObject 객체 컴파일하기 125 | ```swift 126 | let regex = re.compile("this(.+)that") 127 | ``` 128 | ### 문자열 첫 부분부터 패턴 매칭하기 129 | ```swift 130 | if let m = regex.match("this one is different from that") { 131 | m.group() //"this one is different from that" 132 | m.group(1) //" one is different from " 133 | } 134 | ``` 135 | ### 패턴 검색하기 (가장 먼저 매칭되는 패턴) 136 | ```swift 137 | if let m = regex.search("I want this one, not that one") { 138 | m.group() //"this one, not that one" 139 | m.group(1) //" one, not " 140 | } 141 | ``` 142 | ### 매칭되는 모든 패턴 검색하기 143 | ```swift 144 | regex.findall("this or that, this and that") // ["this or that", "this and that"] 145 | ``` 146 | ### 모든 매칭 결과 가져오기 147 | ```swift 148 | for m in regex.finditer("this or that, this and that") { 149 | m.group() // 1st time: "this or that", 2nd time: "this and that" 150 | m.group(1) // 1st time: " or ", 2nd time: " and " 151 | } 152 | ``` 153 | ### 정규식으로 문자열 자르기 154 | ```swift 155 | let regex = re.compile("[\\+\\-\\*/]") 156 | 157 | // By default, will split at all occurrences of the pattern 158 | regex.split("1+2-3*4/5") // ["1", "2", "3", "4", "5"] 159 | 160 | // Setting a maxsplit = 2 161 | regex.split("1+2-3*4/5", 2) // ["1", "2", "3*4/5"] 162 | ``` 163 | ### 패턴 치환하기 164 | ```swift 165 | let regex = re.compile("[Yy]ou") 166 | 167 | // Replacing all occurrences (2 times in this example) 168 | regex.sub("u", "You guys go grap your food") // "u guys go grap ur food" 169 | regex.subn("u", "You guys go grap your food") // ("u guys go grap ur food", 2) 170 | 171 | // Setting maximum replace count = 1 (1 times in this example) 172 | regex.sub("u", "You guys go grap your food", 1) // "u guys go grap your food" 173 | regex.subn("u", "You guys go grap your food", 1) // ("u guys go grap your food", 1) 174 | ``` 175 | 176 | ## 라이센스 177 | 178 | `PySwiftyRegex`는 MIT 라이센스 하에 배포됩니다. 자세한 내용은 [LICENSE](LICENSE) 파일을 참고하세요. 179 | -------------------------------------------------------------------------------- /README-zh.md: -------------------------------------------------------------------------------- 1 | # PySwiftyRegex 2 | [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/PySwiftyRegex.svg)](https://cocoapods.org/pods/PySwiftyRegex) 3 | [![License](https://img.shields.io/cocoapods/l/PySwiftyRegex.svg?style=flat&color=gray)](http://opensource.org/licenses/MIT) 4 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Platform](https://img.shields.io/cocoapods/p/PySwiftyRegex.svg?style=flat)](http://cocoadocs.org/docsets/PySwiftyRegex) 6 | [![Twitter](https://img.shields.io/badge/twitter-@AdamoCheng-blue.svg?style=flat)](http://twitter.com/AdamoCheng) 7 | 8 | 像Python一样简洁高效地作正则处理。 9 | 10 | [English](README.md) 11 | [日本語](README-ja.md) 12 | [한국어](README-ko.md) 13 | 14 | ## 先上代码 15 | 16 | ```swift 17 | import PySwiftyRegex 18 | 19 | if let m = re.search("[Tt]his is (.*?)easy", "I think this is really easy!!!") { 20 | m.group() // "this is really easy" 21 | m.group(1) // "really " 22 | } 23 | ``` 24 | 查看 [常见用例](#more_usage). 25 | 26 | ## 环境 27 | 28 | - iOS 7.0+ / Mac OS X 10.9+ 29 | - Xcode 8.0+ 30 | 31 | > Swift 2.3请使用[0.3.0](../../releases/tag/0.3.0)版。 32 | 33 | ## 导入 34 | > **使用 Embedded frameworks 至少需要 iOS 8 或 OS X Mavericks.** 35 | > 36 | > 如果您的项目需要支持iOS 7但仍想使用 `PySwiftyRegex`, 您需要将源代码文件 [PySwiftyRegex.swift](https://github.com/cezheng/PySwiftyRegex/blob/master/PySwiftyRegex/PySwiftyRegex.swift) 下载并添加到您的Xcode项目中。 37 | 38 | ### CocoaPods(iOS 8+, OS X 10.9+) 39 | 您可以通过 [Cocoapods](http://cocoapods.org/) 来将 `PySwiftyRegex` 添加到您的项目中。 下面是一个示例的`Podfile`: 40 | 41 | ```ruby 42 | platform :ios, '8.0' 43 | use_frameworks! 44 | 45 | target 'MyApp' do 46 | pod 'PySwiftyRegex', '~> 0.2.0' 47 | end 48 | ``` 49 | 50 | 配置好Podfile后执行如下命令: 51 | 52 | ```bash 53 | $ pod install 54 | ``` 55 | 56 | ### Carthage(iOS 8+, OS X 10.9+) 57 | 往 `Cartfile` 或 `Cartfile.private` 中加入如下一行: 58 | 59 | ``` 60 | github "cezheng/PySwiftyRegex" ~> 0.2.0 61 | ``` 62 | 然后执行如下命令: 63 | 64 | ``` 65 | $ carthage update 66 | ``` 67 | 最后将Carthage编译出来的`PySwiftyRegex.framework`拖拽入目标的`General` -> `Embedded Binaries`。 68 | 69 | ## 已实现的re模块方法 70 | 如果您已有 [**re**](https://docs.python.org/2/library/re.html) 模块的使用经验, 那么基本上将这个库导入到项目中就可以直接开始用了。 如果没有,或许可以点击下方的链接传送到Python的文档页面大致了解一下为何re模块会比NSRegualarExpression的API更加好用。 71 | ### [re](https://docs.python.org/2/library/re.html#module-contents) 72 | * [re.compile](https://docs.python.org/2/library/re.html#re.compile) 73 | * [re.search](https://docs.python.org/2/library/re.html#re.search) 74 | * [re.match](https://docs.python.org/2/library/re.html#re.match) 75 | * [re.split](https://docs.python.org/2/library/re.html#re.split) 76 | * [re.findall](https://docs.python.org/2/library/re.html#re.findall) 77 | * [re.finditer](https://docs.python.org/2/library/re.html#re.finditer) 78 | * [re.sub](https://docs.python.org/2/library/re.html#re.sub) 79 | * [re.subn](https://docs.python.org/2/library/re.html#re.subn) 80 | 81 | ### [re.RegexObject](https://docs.python.org/2/library/re.html#regular-expression-objects) 82 | * [search](https://docs.python.org/2/library/re.html#re.RegexObject.search) 83 | * [match](https://docs.python.org/2/library/re.html#re.RegexObject.match) 84 | * [split](https://docs.python.org/2/library/re.html#re.RegexObject.split) 85 | * [findall](https://docs.python.org/2/library/re.html#re.RegexObject.findall) 86 | * [finditer](https://docs.python.org/2/library/re.html#re.RegexObject.finditer) 87 | * [sub](https://docs.python.org/2/library/re.html#re.RegexObject.sub) 88 | * [subn](https://docs.python.org/2/library/re.html#re.RegexObject.subn) 89 | 90 | ### [re.MatchObject](https://docs.python.org/2/library/re.html#match-objects) 91 | * [expand](https://docs.python.org/2/library/re.html#re.MatchObject.expand) 92 | * [group](https://docs.python.org/2/library/re.html#re.MatchObject.group) 93 | * [groups](https://docs.python.org/2/library/re.html#re.MatchObject.groups) 94 | * [span](https://docs.python.org/2/library/re.html#re.MatchObject.span) 95 | 96 | ## 常用方法用例 97 | ### 创建可重复使用的正则表达式对象 98 | ```swift 99 | let regex = re.compile("this(.+)that") 100 | ``` 101 | ### 从字符串起始点开始匹配 102 | ```swift 103 | if let m = regex.match("this one is different from that") { 104 | m.group() //"this one is different from that" 105 | m.group(1) //" one is different from " 106 | } 107 | ``` 108 | ### 在字符串中搜索第一个匹配 109 | ```swift 110 | if let m = regex.search("I want this one, not that one") { 111 | m.group() //"this one, not that one" 112 | m.group(1) //" one, not " 113 | } 114 | ``` 115 | ### 查找所有匹配字串 116 | ```swift 117 | regex.findall("this or that, this and that") // ["this or that", "this and that"] 118 | ``` 119 | ### 获得所有匹配字串的匹配结果 120 | ```swift 121 | for m in regex.finditer("this or that, this and that") { 122 | m.group() // 第1次: "this or that", 第2次: "this and that" 123 | m.group(1) // 第1次: " or ", 第2次: " and " 124 | } 125 | ``` 126 | ### 用正则表达式分割字符串 127 | ```swift 128 | let regex = re.compile("[\\+\\-\\*/]") 129 | 130 | // 默认将做最多次分割 131 | regex.split("1+2-3*4/5") // ["1", "2", "3", "4", "5"] 132 | 133 | // 设定最大分割次数为2 134 | regex.split("1+2-3*4/5", 2) // ["1", "2", "3*4/5"] 135 | ``` 136 | ### 正则替换 137 | ```swift 138 | let regex = re.compile("[Yy]ou") 139 | 140 | // 替换所有匹配 (本例中替换了2次) 141 | regex.sub("u", "You guys go grap your food") // "u guys go grap ur food" 142 | regex.subn("u", "You guys go grap your food") // ("u guys go grap ur food", 2) 143 | 144 | // 设定最大替换次数 (本例中替换了1次) 145 | regex.sub("u", "You guys go grap your food", 1) // "u guys go grap your food" 146 | regex.subn("u", "You guys go grap your food", 1) // ("u guys go grap your food", 1) 147 | ``` 148 | 149 | ## 开源协议 150 | 151 | `PySwiftyRegex` 使用MIT许可协议。 详见 [LICENSE](https://github.com/cezheng/PySwiftyRegex/blob/master/LICENSE) 。 152 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PySwiftyRegex 2 | [![Cocoapods Compatible](https://img.shields.io/cocoapods/v/PySwiftyRegex.svg)](https://cocoapods.org/pods/PySwiftyRegex) 3 | [![License](https://img.shields.io/cocoapods/l/PySwiftyRegex.svg?style=flat&color=gray)](http://opensource.org/licenses/MIT) 4 | [![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 5 | [![Platform](https://img.shields.io/cocoapods/p/PySwiftyRegex.svg?style=flat)](http://cocoadocs.org/docsets/PySwiftyRegex) 6 | [![Twitter](https://img.shields.io/badge/twitter-@AdamoCheng-blue.svg?style=flat)](http://twitter.com/AdamoCheng) 7 | 8 | Easily deal with Regex in Swift in a Pythonic way. 9 | 10 | [简体中文](README-zh.md) 11 | [日本語](README-ja.md) 12 | [한국어](README-ko.md) 13 | 14 | ## This is Easy 15 | 16 | ```swift 17 | import PySwiftyRegex 18 | 19 | if let m = re.search("[Tt]his is (.*?)easy", "I think this is really easy!!!") { 20 | m.group() // "this is really easy" 21 | m.group(1) // "really " 22 | } 23 | ``` 24 | See [More examples](#more_usage). 25 | 26 | ## Requirements 27 | 28 | - iOS 7.0+ / Mac OS X 10.9+ 29 | - Xcode 8.0+ 30 | 31 | < For Swift 2.3 please use version [0.3.0](../../releases/tag/0.3.0). 32 | 33 | 34 | ## Installation 35 | > **Embedded frameworks require a minimum deployment target of iOS 8 or OS X Mavericks.** 36 | > 37 | > To use `PySwiftyRegex` with a project targeting iOS 7, consider using [CocoaSeeds](#cocoaseeds-for-ios7) or copy the [PySwiftyRegex.swift](PySwiftyRegex/PySwiftyRegex.swift) file into your project. 38 | 39 | ### CocoaPods(iOS 8+, OS X 10.9+) 40 | You can use [Cocoapods](http://cocoapods.org/) to install `PySwiftyRegex` by adding it to your to your `Podfile`: 41 | 42 | ```ruby 43 | platform :ios, '8.0' 44 | use_frameworks! 45 | 46 | target 'MyApp' do 47 | pod 'PySwiftyRegex', '~> 1.0.0' 48 | end 49 | ``` 50 | 51 | Then, run the following command: 52 | 53 | ```bash 54 | $ pod install 55 | ``` 56 | 57 | ### Carthage(iOS 8+, OS X 10.9+) 58 | Adding the following line to your `Cartfile` or `Cartfile.private`: 59 | 60 | ``` 61 | github "cezheng/PySwiftyRegex" ~> 1.0.0 62 | ``` 63 | Run the following command: 64 | 65 | ``` 66 | $ carthage update 67 | ``` 68 | Then drag the `PySwiftyRegex.framework` built by Carthage into your target's `General` -> `Embedded Binaries`. 69 | 70 | ### CocoaSeeds (for iOS 7) 71 | 72 | [CocoaSeeds](https://github.com/devxoul/CocoaSeeds) allows you to use Swift libraries in iOS 7 projects. 73 | 74 | Create **Seedfile**: 75 | 76 | ```ruby 77 | target :MyApp do 78 | github 'cezheng/PySwiftyRegex', '1.0.0', :files => 'PySwiftyRegex/PySwiftyRegex.swift' 79 | end 80 | ``` 81 | 82 | Then run the following command: 83 | 84 | ```console 85 | $ seed install 86 | ``` 87 | 88 | Now you can see the PySwiftyRegex.swift file in your Xcode project. Build and enjoy! 89 | 90 | ## Supported re methods 91 | If you are familiar with Python's [**re**](https://docs.python.org/2/library/re.html) module, you are ready to go. If not, you may like to check how Python's re is better than the cumbersome NSRegularExpression's APIs, by clicking at the items below. 92 | ### [re](https://docs.python.org/2/library/re.html#module-contents) 93 | * [re.compile](https://docs.python.org/2/library/re.html#re.compile) 94 | * [re.search](https://docs.python.org/2/library/re.html#re.search) 95 | * [re.match](https://docs.python.org/2/library/re.html#re.match) 96 | * [re.split](https://docs.python.org/2/library/re.html#re.split) 97 | * [re.findall](https://docs.python.org/2/library/re.html#re.findall) 98 | * [re.finditer](https://docs.python.org/2/library/re.html#re.finditer) 99 | * [re.sub](https://docs.python.org/2/library/re.html#re.sub) 100 | * [re.subn](https://docs.python.org/2/library/re.html#re.subn) 101 | 102 | ### [re.RegexObject](https://docs.python.org/2/library/re.html#regular-expression-objects) 103 | * [search](https://docs.python.org/2/library/re.html#re.RegexObject.search) 104 | * [match](https://docs.python.org/2/library/re.html#re.RegexObject.match) 105 | * [split](https://docs.python.org/2/library/re.html#re.RegexObject.split) 106 | * [findall](https://docs.python.org/2/library/re.html#re.RegexObject.findall) 107 | * [finditer](https://docs.python.org/2/library/re.html#re.RegexObject.finditer) 108 | * [sub](https://docs.python.org/2/library/re.html#re.RegexObject.sub) 109 | * [subn](https://docs.python.org/2/library/re.html#re.RegexObject.subn) 110 | 111 | ### [re.MatchObject](https://docs.python.org/2/library/re.html#match-objects) 112 | * [expand](https://docs.python.org/2/library/re.html#re.MatchObject.expand) 113 | * [group](https://docs.python.org/2/library/re.html#re.MatchObject.group) 114 | * [groups](https://docs.python.org/2/library/re.html#re.MatchObject.groups) 115 | * [span](https://docs.python.org/2/library/re.html#re.MatchObject.span) 116 | 117 | ## More Usage Examples 118 | ### Compile a RegexObject for future reuse 119 | ```swift 120 | let regex = re.compile("this(.+)that") 121 | ``` 122 | ### Matching a pattern from beginning 123 | ```swift 124 | if let m = regex.match("this one is different from that") { 125 | m.group() //"this one is different from that" 126 | m.group(1) //" one is different from " 127 | } 128 | ``` 129 | ### Searching a pattern (first match) 130 | ```swift 131 | if let m = regex.search("I want this one, not that one") { 132 | m.group() //"this one, not that one" 133 | m.group(1) //" one, not " 134 | } 135 | ``` 136 | ### Find all occurrences of a pattern 137 | ```swift 138 | regex.findall("this or that, this and that") // ["this or that", "this and that"] 139 | ``` 140 | ### Get match results for all occurrences of a pattern 141 | ```swift 142 | for m in regex.finditer("this or that, this and that") { 143 | m.group() // 1st time: "this or that", 2nd time: "this and that" 144 | m.group(1) // 1st time: " or ", 2nd time: " and " 145 | } 146 | ``` 147 | ### Splitting a string with pattern 148 | ```swift 149 | let regex = re.compile("[\\+\\-\\*/]") 150 | 151 | // By default, will split at all occurrences of the pattern 152 | regex.split("1+2-3*4/5") // ["1", "2", "3", "4", "5"] 153 | 154 | // Setting a maxsplit = 2 155 | regex.split("1+2-3*4/5", 2) // ["1", "2", "3*4/5"] 156 | ``` 157 | ### Replacing a pattern 158 | ```swift 159 | let regex = re.compile("[Yy]ou") 160 | 161 | // Replacing all occurrences (2 times in this example) 162 | regex.sub("u", "You guys go grap your food") // "u guys go grap ur food" 163 | regex.subn("u", "You guys go grap your food") // ("u guys go grap ur food", 2) 164 | 165 | // Setting maximum replace count = 1 (1 times in this example) 166 | regex.sub("u", "You guys go grap your food", 1) // "u guys go grap your food" 167 | regex.subn("u", "You guys go grap your food", 1) // ("u guys go grap your food", 1) 168 | ``` 169 | 170 | ## License 171 | 172 | `PySwiftyRegex` is released under the MIT license. See [LICENSE](LICENSE) for details. 173 | --------------------------------------------------------------------------------